tst_dumpers.cpp 273 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
Bill King's avatar
Bill King committed
2
**
3 4
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
Bill King's avatar
Bill King committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
Bill King's avatar
Bill King committed
7
**
hjk's avatar
hjk committed
8 9 10 11
** 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
12 13 14
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
Bill King's avatar
Bill King committed
15
**
16 17 18 19 20 21 22
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
Bill King's avatar
Bill King committed
23
**
hjk's avatar
hjk committed
24
****************************************************************************/
Bill King's avatar
Bill King committed
25

hjk's avatar
hjk committed
26
#include "debuggerprotocol.h"
27
#include "simplifytype.h"
28 29
#include "watchdata.h"
#include "watchutils.h"
30

31
#ifdef Q_OS_WIN
32
#include <utils/environment.h>
33
#ifdef Q_CC_MSVC
34 35 36
#include <utils/qtcprocess.h>
#include <utils/fileutils.h>
#include <utils/synchronousprocess.h>
37
#endif // Q_CC_MSVC
38
#endif // Q_OS_WIN
39

40
#include <QtTest>
41
#include <math.h>
42

43
#define MSKIP_SINGLE(x) do { disarm(); QSKIP(x); } while (0)
44

45
using namespace Debugger;
hjk's avatar
hjk committed
46
using namespace Internal;
47

48
#ifdef Q_CC_MSVC
49

50
// Copied from abstractmsvctoolchain.cpp to avoid plugin dependency.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
static bool generateEnvironmentSettings(Utils::Environment &env,
                                        const QString &batchFile,
                                        const QString &batchArgs,
                                        QMap<QString, QString> &envPairs)
{
    // Create a temporary file name for the output. Use a temporary file here
    // as I don't know another way to do this in Qt...
    // Note, can't just use a QTemporaryFile all the way through as it remains open
    // internally so it can't be streamed to later.
    QString tempOutFile;
    QTemporaryFile* pVarsTempFile = new QTemporaryFile(QDir::tempPath() + QLatin1String("/XXXXXX.txt"));
    pVarsTempFile->setAutoRemove(false);
    pVarsTempFile->open();
    pVarsTempFile->close();
    tempOutFile = pVarsTempFile->fileName();
    delete pVarsTempFile;

    // Create a batch file to create and save the env settings
    Utils::TempFileSaver saver(QDir::tempPath() + QLatin1String("/XXXXXX.bat"));

    QByteArray call = "call ";
    call += Utils::QtcProcess::quoteArg(batchFile).toLocal8Bit();
    if (!batchArgs.isEmpty()) {
        call += ' ';
        call += batchArgs.toLocal8Bit();
    }
    saver.write(call + "\r\n");

    const QByteArray redirect = "set > " + Utils::QtcProcess::quoteArg(
                                    QDir::toNativeSeparators(tempOutFile)).toLocal8Bit() + "\r\n";
    saver.write(redirect);
    if (!saver.finalize()) {
        qWarning("%s: %s", Q_FUNC_INFO, qPrintable(saver.errorString()));
        return false;
    }

    Utils::QtcProcess run;
    // As of WinSDK 7.1, there is logic preventing the path from being set
    // correctly if "ORIGINALPATH" is already set. That can cause problems
    // if Creator is launched within a session set up by setenv.cmd.
    env.unset(QLatin1String("ORIGINALPATH"));
    run.setEnvironment(env);
    const QString cmdPath = QString::fromLocal8Bit(qgetenv("COMSPEC"));
    // Windows SDK setup scripts require command line switches for environment expansion.
    QString cmdArguments = QLatin1String(" /E:ON /V:ON /c \"");
    cmdArguments += QDir::toNativeSeparators(saver.fileName());
    cmdArguments += QLatin1Char('"');
    run.setCommand(cmdPath, cmdArguments);
    run.start();

    if (!run.waitForStarted()) {
        qWarning("%s: Unable to run '%s': %s", Q_FUNC_INFO, qPrintable(batchFile),
                 qPrintable(run.errorString()));
        return false;
    }
    if (!run.waitForFinished()) {
        qWarning("%s: Timeout running '%s'", Q_FUNC_INFO, qPrintable(batchFile));
        Utils::SynchronousProcess::stopProcess(run);
        return false;
    }
    // The SDK/MSVC scripts do not return exit codes != 0. Check on stdout.
    const QByteArray stdOut = run.readAllStandardOutput();
    if (!stdOut.isEmpty() && (stdOut.contains("Unknown") || stdOut.contains("Error")))
        qWarning("%s: '%s' reports:\n%s", Q_FUNC_INFO, call.constData(), stdOut.constData());

    //
    // Now parse the file to get the environment settings
    QFile varsFile(tempOutFile);
    if (!varsFile.open(QIODevice::ReadOnly))
        return false;

    QRegExp regexp(QLatin1String("(\\w*)=(.*)"));
    while (!varsFile.atEnd()) {
        const QString line = QString::fromLocal8Bit(varsFile.readLine()).trimmed();
        if (regexp.exactMatch(line)) {
            const QString varName = regexp.cap(1);
            const QString varValue = regexp.cap(2);

            if (!varValue.isEmpty())
                envPairs.insert(varName, varValue);
        }
    }

    // Tidy up and remove the file
    varsFile.close();
    varsFile.remove();

    return true;
}

141 142 143 144 145

#ifndef CDBEXT_PATH
#define CDBEXT_PATH ""
#endif

146 147
#endif // Q_CC_MSVC

hjk's avatar
hjk committed
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
struct VersionBase
{
    // Minimum and maximum are inclusive.
    VersionBase(int minimum = 0, int maximum = INT_MAX)
    {
        isRestricted = minimum != 0 || maximum != INT_MAX;
        max = maximum;
        min = minimum;
    }

    bool covers(int what) const
    {
        return !isRestricted || (min <= what && what <= max);
    }

    bool isRestricted;
    int min;
    int max;
};

struct QtVersion : VersionBase
{
170
    explicit QtVersion(int minimum = 0, int maximum = INT_MAX)
hjk's avatar
hjk committed
171 172 173 174
        : VersionBase(minimum, maximum)
    {}
};

hjk's avatar
hjk committed
175 176
struct DwarfVersion : VersionBase
{
177
    explicit DwarfVersion(int minimum = 0, int maximum = INT_MAX)
hjk's avatar
hjk committed
178 179 180 181
        : VersionBase(minimum, maximum)
    {}
};

hjk's avatar
hjk committed
182 183
struct GccVersion : VersionBase
{
184
    explicit GccVersion(int minimum = 0, int maximum = INT_MAX)
hjk's avatar
hjk committed
185 186 187 188
        : VersionBase(minimum, maximum)
    {}
};

189 190
struct ClangVersion : VersionBase
{
191
    explicit ClangVersion(int minimum = 0, int maximum = INT_MAX)
192 193 194 195
        : VersionBase(minimum, maximum)
    {}
};

196 197 198 199 200 201 202
struct MsvcVersion : VersionBase
{
    explicit MsvcVersion(int minimum = 0, int maximum = INT_MAX)
        : VersionBase(minimum, maximum)
    {}
};

hjk's avatar
hjk committed
203 204
struct GdbVersion : VersionBase
{
205
    explicit GdbVersion(int minimum = 0, int maximum = INT_MAX)
hjk's avatar
hjk committed
206 207 208 209 210 211
        : VersionBase(minimum, maximum)
    {}
};

struct LldbVersion : VersionBase
{
212
    explicit LldbVersion(int minimum = 0, int maximum = INT_MAX)
hjk's avatar
hjk committed
213 214 215 216
        : VersionBase(minimum, maximum)
    {}
};

217 218
struct BoostVersion : VersionBase
{
219
    explicit BoostVersion(int minimum = 0, int maximum = INT_MAX)
220 221 222 223
        : VersionBase(minimum, maximum)
    {}
};

hjk's avatar
hjk committed
224
static QString noValue = "\001";
225

226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
enum DebuggerEngine
{
    NoEngine = 0x00,

    GdbEngine = 0x01,
    CdbEngine = 0x02,
    LldbEngine = 0x04,

    AllEngines = GdbEngine | CdbEngine | LldbEngine,

    NoCdbEngine = AllEngines & (~CdbEngine),
    NoLldbEngine = AllEngines & (~LldbEngine),
    NoGdbEngine = AllEngines & (~GdbEngine)
};

hjk's avatar
hjk committed
241 242
struct Context
{
243
    Context(DebuggerEngine engine) : engine(engine) {}
hjk's avatar
hjk committed
244 245 246 247
    QString nameSpace;
    int qtVersion = 0;
    int gccVersion = 0;
    int clangVersion = 0;
248
    int msvcVersion = 0;
hjk's avatar
hjk committed
249
    int boostVersion = 0;
250
    DebuggerEngine engine;
hjk's avatar
hjk committed
251 252
};

hjk's avatar
hjk committed
253 254
struct Name
{
hjk's avatar
hjk committed
255
    Name() : name(noValue) {}
hjk's avatar
hjk committed
256 257
    Name(const char *str) : name(QString::fromUtf8(str)) {}
    Name(const QString &ba) : name(ba) {}
hjk's avatar
hjk committed
258

hjk's avatar
hjk committed
259
    bool matches(const QString &actualName0, const Context &context) const
hjk's avatar
hjk committed
260
    {
hjk's avatar
hjk committed
261 262
        QString actualName = actualName0;
        QString expectedName = name;
hjk's avatar
hjk committed
263
        expectedName.replace("@Q", context.nameSpace + 'Q');
hjk's avatar
hjk committed
264 265 266
        return actualName == expectedName;
    }

hjk's avatar
hjk committed
267
    QString name;
hjk's avatar
hjk committed
268 269
};

hjk's avatar
hjk committed
270
static Name nameFromIName(const QString &iname)
hjk's avatar
hjk committed
271 272
{
    int pos = iname.lastIndexOf('.');
hjk's avatar
hjk committed
273
    return Name(pos == -1 ? iname : iname.mid(pos + 1));
hjk's avatar
hjk committed
274 275
}

hjk's avatar
hjk committed
276
static QString parentIName(const QString &iname)
hjk's avatar
hjk committed
277 278
{
    int pos = iname.lastIndexOf('.');
hjk's avatar
hjk committed
279
    return pos == -1 ? QString() : iname.left(pos);
hjk's avatar
hjk committed
280 281
}

hjk's avatar
hjk committed
282
struct Value
283
{
hjk's avatar
hjk committed
284
    Value() : value(noValue) {}
285 286
    Value(const char *str) : value(QLatin1String(str)) {}
    Value(const QString &str) : value(str) {}
287

hjk's avatar
hjk committed
288
    bool matches(const QString &actualValue0, const Context &context) const
289
    {
hjk's avatar
hjk committed
290
        if (value == noValue)
291
            return true;
hjk's avatar
hjk committed
292 293

        if (context.qtVersion) {
hjk's avatar
hjk committed
294
            if (qtVersion == 4) {
hjk's avatar
hjk committed
295 296 297 298
                if (context.qtVersion < 0x40000 || context.qtVersion >= 0x50000) {
                    //QWARN("Qt 4 specific case skipped");
                    return true;
                }
hjk's avatar
hjk committed
299
            } else if (qtVersion == 5) {
hjk's avatar
hjk committed
300 301 302 303 304 305
                if (context.qtVersion < 0x50000 || context.qtVersion >= 0x60000) {
                    //QWARN("Qt 5 specific case skipped");
                    return true;
                }
            }
        }
306
        QString actualValue = actualValue0;
hjk's avatar
hjk committed
307
        if (actualValue == " ")
308
            actualValue.clear(); // FIXME: Remove later.
309
        QString expectedValue = value;
310
        if (substituteNamespace)
hjk's avatar
hjk committed
311
            expectedValue.replace('@', context.nameSpace);
hjk's avatar
hjk committed
312

313 314 315 316 317 318 319 320 321 322
        if (isPattern) {
            expectedValue.replace("(", "!");
            expectedValue.replace(")", "!");
            actualValue.replace("(", "!");
            actualValue.replace(")", "!");
            //QWARN(qPrintable("MATCH EXP: " + expectedValue + "   ACT: " + actualValue));
            //QWARN(QRegExp(expectedValue).exactMatch(actualValue) ? "OK" : "NOT OK");
            return QRegExp(expectedValue).exactMatch(actualValue);
        }

323
        if (hasPtrSuffix)
hjk's avatar
hjk committed
324 325
            return actualValue.startsWith(expectedValue + " @0x")
                || actualValue.startsWith(expectedValue + "@0x");
326 327 328 329 330 331 332 333 334 335 336 337

        if (isFloatValue) {
            double f1 = fabs(expectedValue.toDouble());
            double f2 = fabs(actualValue.toDouble());
            //qDebug() << "expected float: " << qPrintable(expectedValue) << f1;
            //qDebug() << "actual   float: " << qPrintable(actualValue) << f2;
            if (f1 < f2)
                std::swap(f1, f2);
            return f1 - f2 <= 0.01 * f2;
        }


338
        return actualValue == expectedValue;
339 340
    }

341
    QString value;
hjk's avatar
hjk committed
342 343 344
    bool hasPtrSuffix = false;
    bool isFloatValue = false;
    bool substituteNamespace = true;
345
    bool isPattern = false;
hjk's avatar
hjk committed
346
    int qtVersion = 0;
347 348
};

349 350 351 352 353
struct ValuePattern : Value
{
    ValuePattern(const QString &ba) : Value(ba) { isPattern = true; }
};

354 355 356
struct Pointer : Value
{
    Pointer() { hasPtrSuffix = true; }
hjk's avatar
hjk committed
357
    Pointer(const QString &value) : Value(value) { hasPtrSuffix = true; }
358 359
};

360 361 362
struct FloatValue : Value
{
    FloatValue() { isFloatValue = true; }
hjk's avatar
hjk committed
363
    FloatValue(const QString &value) : Value(value) { isFloatValue = true; }
364 365
};

hjk's avatar
hjk committed
366 367
struct Value4 : Value
{
hjk's avatar
hjk committed
368
    Value4(const QString &value) : Value(value) { qtVersion = 4; }
hjk's avatar
hjk committed
369 370 371 372
};

struct Value5 : Value
{
hjk's avatar
hjk committed
373
    Value5(const QString &value) : Value(value) { qtVersion = 5; }
hjk's avatar
hjk committed
374 375
};

376 377
struct UnsubstitutedValue : Value
{
hjk's avatar
hjk committed
378
    UnsubstitutedValue(const QString &value) : Value(value) { substituteNamespace = false; }
379 380
};

381 382
struct Optional {};

383 384
struct Type
{
385 386 387
    Type() {}
    Type(const char *str) : type(QString::fromUtf8(str)) {}
    Type(const QString &ba) : type(ba) {}
hjk's avatar
hjk committed
388

hjk's avatar
hjk committed
389 390
    bool matches(const QString &actualType0, const Context &context,
                 bool fullNamespaceMatch = true) const
391
    {
392
        if (context.qtVersion) {
hjk's avatar
hjk committed
393
            if (qtVersion == 4) {
394 395 396 397
                if (context.qtVersion < 0x40000 || context.qtVersion >= 0x50000) {
                    //QWARN("Qt 4 specific case skipped");
                    return true;
                }
hjk's avatar
hjk committed
398
            } else if (qtVersion == 5) {
399 400 401 402 403 404
                if (context.qtVersion < 0x50000 || context.qtVersion >= 0x60000) {
                    //QWARN("Qt 5 specific case skipped");
                    return true;
                }
            }
        }
hjk's avatar
hjk committed
405
        QString actualType = simplifyType(actualType0);
406
        actualType.replace(' ', "");
hjk's avatar
hjk committed
407
        actualType.replace("const", "");
408 409 410 411 412
        QString expectedType;
        if (aliasName.isEmpty() || context.engine == CdbEngine)
            expectedType = type;
        else
            expectedType = aliasName;
413
        expectedType.replace(' ', "");
414
        expectedType.replace("const", "");
hjk's avatar
hjk committed
415
        expectedType.replace('@', context.nameSpace);
416

hjk's avatar
hjk committed
417 418
        if (isPattern)
            return QRegExp(expectedType).exactMatch(actualType);
419

420 421 422 423 424
        if (fullNamespaceMatch)
            expectedType.replace('?', context.nameSpace);
        else
            expectedType.replace('?', "");

425 426 427 428 429 430 431 432 433 434 435
        if (actualType == expectedType)
            return true;

        // LLDB 3.7 on Linux doesn't get the namespace right in QMapNode:
        // t = lldb.target.FindFirstType('Myns::QMapNode<int, CustomStruct>')
        // t.GetName() -> QMapNode<int, CustomStruct> (no Myns::)
        // So try again without namespace.
        if (fullNamespaceMatch)
            return matches(actualType0, context, false);

        return false;
436
    }
437

hjk's avatar
hjk committed
438
    QString type;
439
    QString aliasName;
440 441
    int qtVersion = 0;
    bool isPattern = false;
442 443 444 445
};

struct Type4 : Type
{
hjk's avatar
hjk committed
446
    Type4(const QString &ba) : Type(ba) { qtVersion = 4; }
447 448 449 450
};

struct Type5 : Type
{
hjk's avatar
hjk committed
451
    Type5(const QString &ba) : Type(ba) { qtVersion = 5; }
452 453
};

hjk's avatar
hjk committed
454
struct TypePattern : Type
455
{
hjk's avatar
hjk committed
456
    TypePattern(const QString &ba) : Type(ba) { isPattern = true; }
457 458
};

459 460 461 462 463 464 465
struct TypeDef : Type
{
    TypeDef(const QString &typeName, const QString &aliasName) : Type(typeName)
    {
        this->aliasName = aliasName;
    }
};
466

467 468 469 470 471 472 473 474 475
struct RequiredMessage
{
    RequiredMessage() {}

    RequiredMessage(const QString &message) : message(message) {}

    QString message;
};

hjk's avatar
hjk committed
476
struct Check
477 478 479
{
    Check() {}

hjk's avatar
hjk committed
480
    Check(const QString &iname, const Value &value, const Type &type)
hjk's avatar
hjk committed
481
        : iname(iname), expectedName(nameFromIName(iname)),
482
          expectedValue(value), expectedType(type)
hjk's avatar
hjk committed
483 484
    {}

hjk's avatar
hjk committed
485
    Check(const QString &iname, const Name &name,
486
         const Value &value, const Type &type)
487
        : iname(iname), expectedName(name),
488
          expectedValue(value), expectedType(type)
489 490
    {}

491
    bool matches(DebuggerEngine engine, int debuggerVersion, const Context &context) const
492
    {
hjk's avatar
hjk committed
493 494
        return (engine & enginesForCheck)
            && debuggerVersionForCheck.covers(debuggerVersion)
495 496
            && gccVersionForCheck.covers(context.gccVersion)
            && clangVersionForCheck.covers(context.clangVersion)
497
            && msvcVersionForCheck.covers(context.msvcVersion)
498
            && qtVersionForCheck.covers(context.qtVersion);
499 500
    }

501 502 503 504 505 506
    const Check &operator%(Optional) const
    {
        optionallyPresent = true;
        return *this;
    }

507
    const Check &operator%(DebuggerEngine engine) const
508
    {
hjk's avatar
hjk committed
509
        enginesForCheck = engine;
510
        return *this;
511
    }
512

513
    const Check &operator%(GdbVersion version) const
hjk's avatar
hjk committed
514 515 516 517 518 519
    {
        enginesForCheck = GdbEngine;
        debuggerVersionForCheck = version;
        return *this;
    }

520
    const Check &operator%(LldbVersion version) const
521 522 523 524 525 526
    {
        enginesForCheck = LldbEngine;
        debuggerVersionForCheck = version;
        return *this;
    }

527
    const Check &operator%(GccVersion version) const
528
    {
529
        enginesForCheck = NoCdbEngine;
530 531 532 533
        gccVersionForCheck = version;
        return *this;
    }

534
    const Check &operator%(ClangVersion version) const
535 536 537 538 539 540
    {
        enginesForCheck = GdbEngine;
        clangVersionForCheck = version;
        return *this;
    }

541 542 543 544 545 546 547
    const Check &operator%(MsvcVersion version) const
    {
        enginesForCheck = CdbEngine;
        msvcVersionForCheck = version;
        return *this;
    }

548
    const Check &operator%(BoostVersion version) const
549 550 551 552 553
    {
        boostVersionForCheck = version;
        return *this;
    }

554
    const Check &operator%(QtVersion version) const
555 556 557 558 559
    {
        qtVersionForCheck = version;
        return *this;
    }

hjk's avatar
hjk committed
560
    QString iname;
hjk's avatar
hjk committed
561
    Name expectedName;
562
    Value expectedValue;
563
    Type expectedType;
hjk's avatar
hjk committed
564 565 566 567 568

    mutable int enginesForCheck = AllEngines;
    mutable VersionBase debuggerVersionForCheck;
    mutable VersionBase gccVersionForCheck;
    mutable VersionBase clangVersionForCheck;
569
    mutable VersionBase msvcVersionForCheck;
hjk's avatar
hjk committed
570 571 572
    mutable QtVersion qtVersionForCheck;
    mutable BoostVersion boostVersionForCheck;
    mutable bool optionallyPresent = false;
573 574
};

hjk's avatar
hjk committed
575
struct CheckType : public Check
576
{
hjk's avatar
hjk committed
577
    CheckType(const QByteArray &iname, const Name &name,
578
         const Type &type)
579 580
        : Check(iname, name, noValue, type)
    {}
581

582
    CheckType(const QByteArray &iname, const Type &type)
hjk's avatar
hjk committed
583 584 585 586
        : Check(iname, noValue, type)
    {}
};

hjk's avatar
hjk committed
587 588 589
const QtVersion Qt4 = QtVersion(0, 0x4ffff);
const QtVersion Qt5 = QtVersion(0x50000);

590 591 592
struct Check4 : Check
{
    Check4(const QByteArray &iname, const Value &value, const Type &type)
hjk's avatar
hjk committed
593
        : Check(iname, value, type) { qtVersionForCheck = Qt4; }
594 595

    Check4(const QByteArray &iname, const Name &name, const Value &value, const Type &type)
hjk's avatar
hjk committed
596
        : Check(iname, name, value, type) { qtVersionForCheck = Qt4; }
597 598 599 600 601
};

struct Check5 : Check
{
    Check5(const QByteArray &iname, const Value &value, const Type &type)
hjk's avatar
hjk committed
602
        : Check(iname, value, type) { qtVersionForCheck = Qt5; }
603 604

    Check5(const QByteArray &iname, const Name &name, const Value &value, const Type &type)
hjk's avatar
hjk committed
605
        : Check(iname, name, value, type) { qtVersionForCheck = Qt5; }
606 607 608

};

hjk's avatar
hjk committed
609
struct Profile
hjk's avatar
hjk committed
610 611 612
{
    Profile(const QByteArray &contents) : contents(contents) {}

613
    QByteArray includes;
hjk's avatar
hjk committed
614
    QByteArray contents;
615 616
};

hjk's avatar
hjk committed
617

hjk's avatar
hjk committed
618 619
struct Cxx11Profile : public Profile
{
620 621 622 623 624 625
    Cxx11Profile()
      : Profile("greaterThan(QT_MAJOR_VERSION,4): CONFIG += c++11\n"
                "else: QMAKE_CXXFLAGS += -std=c++0x\n")
    {}
};

626 627 628
struct BoostProfile : public Profile
{
    BoostProfile()
629 630 631 632 633 634 635
      : Profile(QByteArray())
    {
        const QByteArray &boostIncPath = qgetenv("QTC_BOOST_INCLUDE_PATH_FOR_TEST");
        if (!boostIncPath.isEmpty())
            contents = QByteArray("INCLUDEPATH += ") + boostIncPath.constData();
        else
            contents = "macx:INCLUDEPATH += /usr/local/include";
636 637 638
        const QByteArray &boostLibPath = qgetenv("QTC_BOOST_LIBRARY_PATH_FOR_TEST");
        if (!boostLibPath.isEmpty())
            contents += QByteArray("\nLIBS += \"-L") + boostLibPath.constData() + QByteArray("\"");
639
        includes = "#include <boost/version.hpp>\n";
640
    }
641 642
};

643
struct MacLibCppProfile : public Profile
644
{
645
    MacLibCppProfile()
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660
      : Profile("macx {\n"
                "QMAKE_CXXFLAGS += -stdlib=libc++\n"
                "LIBS += -stdlib=libc++\n"
                "QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.7\n"
                "QMAKE_IOS_DEPLOYMENT_TARGET = 10.7\n"
                "QMAKE_CFLAGS -= -mmacosx-version-min=10.6\n"
                "QMAKE_CFLAGS += -mmacosx-version-min=10.7\n"
                "QMAKE_CXXFLAGS -= -mmacosx-version-min=10.6\n"
                "QMAKE_CXXFLAGS += -mmacosx-version-min=10.7\n"
                "QMAKE_OBJECTIVE_CFLAGS -= -mmacosx-version-min=10.6\n"
                "QMAKE_OBJECTIVE_CFLAGS += -mmacosx-version-min=10.7\n"
                "QMAKE_LFLAGS -= -mmacosx-version-min=10.6\n"
                "QMAKE_LFLAGS += -mmacosx-version-min=10.7\n"
                "}")
    {}
hjk's avatar
hjk committed
661 662
};

663
struct ForceC {};
hjk's avatar
hjk committed
664
struct EigenProfile {};
665
struct UseDebugImage {};
hjk's avatar
hjk committed
666
struct DwarfProfile { explicit DwarfProfile(int v) : version(v) {} int version; };
667

hjk's avatar
hjk committed
668 669 670
struct CoreProfile {};
struct CorePrivateProfile {};
struct GuiProfile {};
671
struct GuiPrivateProfile {};
hjk's avatar
hjk committed
672
struct NetworkProfile {};
673 674
struct QmlProfile {};
struct QmlPrivateProfile {};
hjk's avatar
hjk committed
675
struct SqlProfile {};
hjk's avatar
hjk committed
676

677
struct NimProfile {};
678

679
struct BigArrayProfile {};
hjk's avatar
hjk committed
680

681
class Data
682
{
hjk's avatar
hjk committed
683 684
public:
    Data() {}
685

hjk's avatar
hjk committed
686
    Data(const QString &includes, const QString &code)
hjk's avatar
hjk committed
687
        : includes(includes), code(code)
hjk's avatar
hjk committed
688
    {}
689

hjk's avatar
hjk committed
690
    const Data &operator+(const Check &check) const
691
    {
692
        checks.append(check);
693 694 695
        return *this;
    }

696 697 698 699 700 701
    const Data &operator+(const RequiredMessage &check) const
    {
        requiredMessages.append(check);
        return *this;
    }

hjk's avatar
hjk committed
702
    const Data &operator+(const Profile &profile) const
hjk's avatar
hjk committed
703 704
    {
        profileExtra += profile.contents;
705
        includes += profile.includes;
hjk's avatar
hjk committed
706 707 708
        return *this;
    }

hjk's avatar
hjk committed
709
    const Data &operator+(const QtVersion &qtVersion) const
710 711 712 713 714
    {
        neededQtVersion = qtVersion;
        return *this;
    }

hjk's avatar
hjk committed
715
    const Data &operator+(const GccVersion &gccVersion) const
716 717 718 719 720
    {
        neededGccVersion = gccVersion;
        return *this;
    }

721 722 723 724 725 726
    const Data &operator+(const ClangVersion &clangVersion) const
    {
        neededClangVersion = clangVersion;
        return *this;
    }

727 728 729 730 731 732
    const Data &operator+(const MsvcVersion &msvcVersion) const
    {
        neededMsvcVersion = msvcVersion;
        return *this;
    }

hjk's avatar
hjk committed
733
    const Data &operator+(const GdbVersion &gdbVersion) const
734 735 736 737 738
    {
        neededGdbVersion = gdbVersion;
        return *this;
    }

hjk's avatar
hjk committed
739
    const Data &operator+(const LldbVersion &lldbVersion) const
hjk's avatar
hjk committed
740 741 742 743 744
    {
        neededLldbVersion = lldbVersion;
        return *this;
    }

745 746 747 748 749 750
    const Data &operator+(const BoostVersion &boostVersion) const
    {
        neededBoostVersion = boostVersion;
        return *this;
    }

hjk's avatar
hjk committed
751 752 753 754 755 756
    const Data &operator+(const DwarfVersion &dwarfVersion) const
    {
        neededDwarfVersion = dwarfVersion;
        return *this;
    }

hjk's avatar
hjk committed
757
    const Data &operator+(const DebuggerEngine &enginesForTest) const
hjk's avatar
hjk committed
758
    {
759
        engines = enginesForTest;
hjk's avatar
hjk committed
760 761 762
        return *this;
    }

hjk's avatar
hjk committed
763
    const Data &operator+(const EigenProfile &) const
hjk's avatar
hjk committed
764 765
    {
        profileExtra +=
hjk's avatar
hjk committed
766
            "exists(/usr/include/eigen3/Eigen/Core) {\n"
767
            "    DEFINES += HAS_EIGEN\n"
hjk's avatar
hjk committed
768 769 770
            "    INCLUDEPATH += /usr/include/eigen3\n"
            "}\n"
            "exists(/usr/local/include/eigen3/Eigen/Core) {\n"
771
            "    DEFINES += HAS_EIGEN\n"
hjk's avatar
hjk committed
772 773 774 775
            "    INCLUDEPATH += /usr/local/include/eigen3\n"
            "}\n"
            "\n"
            "exists(/usr/include/eigen2/Eigen/Core) {\n"
776
            "    DEFINES += HAS_EIGEN\n"
hjk's avatar
hjk committed
777 778 779
            "    INCLUDEPATH += /usr/include/eigen2\n"
            "}\n"
            "exists(/usr/local/include/eigen2/Eigen/Core) {\n"
780
            "    DEFINES += HAS_EIGEN\n"
hjk's avatar
hjk committed
781 782
            "    INCLUDEPATH += /usr/local/include/eigen2\n"
            "}\n";
hjk's avatar
hjk committed
783 784 785 786

        return *this;
    }

hjk's avatar
hjk committed
787 788 789 790 791 792 793 794
    const Data &operator+(const DwarfProfile &p)
    {
        profileExtra +=
            "QMAKE_CXXFLAGS -= -g\n"
            "QMAKE_CXXFLAGS += -gdwarf-" + QString::number(p.version) + "\n";
        return *this;
    }

hjk's avatar
hjk committed
795
    const Data &operator+(const UseDebugImage &) const
796 797 798 799 800
    {
        useDebugImage = true;
        return *this;
    }

hjk's avatar
hjk committed
801
    const Data &operator+(const CoreProfile &) const
hjk's avatar
hjk committed
802
    {
803
        profileExtra += "QT += core\n";
hjk's avatar
hjk committed
804 805

        useQt = true;
806 807
        useQHash = true;

hjk's avatar
hjk committed
808 809 810
        return *this;
    }

hjk's avatar
hjk committed
811
    const Data &operator+(const NetworkProfile &) const
hjk's avatar
hjk committed
812
    {
813
        profileExtra += "QT += core network\n";
hjk's avatar
hjk committed
814 815 816 817 818 819 820

        useQt = true;
        useQHash = true;

        return *this;
    }

hjk's avatar
hjk committed
821 822 823 824 825 826 827 828 829
    const Data &operator+(const SqlProfile &) const
    {
        profileExtra += "QT += core sql\n";

        useQt = true;

        return *this;
    }

830 831 832 833 834 835
    const Data &operator+(const BigArrayProfile &) const
    {
        this->bigArray = true;
        return *this;
    }

hjk's avatar
hjk committed
836
    const Data &operator+(const GuiProfile &) const
hjk's avatar
hjk committed
837
    {
hjk's avatar
hjk committed
838
        this->operator+(CoreProfile());
hjk's avatar
hjk committed
839 840 841 842 843 844 845
        profileExtra +=
            "QT += gui\n"
            "greaterThan(QT_MAJOR_VERSION, 4):QT *= widgets\n";

        return *this;
    }

hjk's avatar
hjk committed
846
    const Data &operator+(const CorePrivateProfile &) const
hjk's avatar
hjk committed
847
    {
hjk's avatar
hjk committed
848
        this->operator+(CoreProfile());
hjk's avatar
hjk committed
849 850
        profileExtra +=
            "greaterThan(QT_MAJOR_VERSION, 4) {\n"
851
            "  QT += core-private\n"
hjk's avatar
hjk committed
852 853 854 855 856 857
            "  CONFIG += no_private_qt_headers_warning\n"
            "}";

        return *this;
    }

858 859 860 861 862 863 864 865 866 867 868 869
    const Data &operator+(const GuiPrivateProfile &) const
    {
        this->operator+(GuiProfile());
        profileExtra +=
            "greaterThan(QT_MAJOR_VERSION, 4) {\n"
            "  QT += gui-private\n"
            "  CONFIG += no_private_qt_headers_warning\n"
            "}";

        return *this;
    }

870 871
    const Data &operator+(const QmlProfile &) const
    {
Orgad Shaneh's avatar
Orgad Shaneh committed
872
        this->operator+(CoreProfile());
873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892
        profileExtra +=
            "greaterThan(QT_MAJOR_VERSION, 4) {\n"
            "  QT += qml\n"
            "}";

        return *this;
    }

    const Data &operator+(const QmlPrivateProfile &) const
    {
        this->operator+(QmlProfile());
        profileExtra +=
            "greaterThan(QT_MAJOR_VERSION, 4) {\n"
            "  QT += qml-private\n"
            "  CONFIG += no_private_qt_headers_warning\n"
            "}";

        return *this;
    }

hjk's avatar
hjk committed
893
    const Data &operator+(const ForceC &) const
894
    {
895
        mainFile = "main.c";
896 897 898
        return *this;
    }

hjk's avatar
hjk committed
899
public:
900 901 902 903 904 905 906 907 908 909 910 911
    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.
912
    mutable MsvcVersion neededMsvcVersion;   // DEC.
913
    mutable BoostVersion neededBoostVersion; // DEC. 105400 for 1.54.0
hjk's avatar
hjk committed
914
    mutable DwarfVersion neededDwarfVersion; // DEC. 105400 for 1.54.0
915 916 917 918 919 920 921 922 923

    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";

hjk's avatar
hjk committed
924 925 926
    mutable QString profileExtra;
    mutable QString includes;
    mutable QString code;
927

928
    mutable QList<Check> checks;
929
    mutable QList<RequiredMessage> requiredMessages;
hjk's avatar
hjk committed
930 931
};

932 933
struct TempStuff
{
934 935 936
    TempStuff(const char *tag) : buildTemp(QLatin1String("qt_tst_dumpers_")
                                           + QLatin1String(tag)
                                           + QLatin1Char('_'))
937
    {
938
        buildPath = QDir::currentPath() + QLatin1Char('/')  + buildTemp.path();
939 940 941 942
        buildTemp.setAutoRemove(false);
        QVERIFY(!buildPath.isEmpty());
    }