cppcompletion_test.cpp 83.5 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
7
**
hjk's avatar
hjk committed
8 9 10 11 12 13 14
** 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.
15 16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17 18 19 20 21 22 23 24 25
** 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
26 27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
29 30

#include "cpptoolsplugin.h"
31
#include "cppcompletionassist.h"
32
#include "cppmodelmanager.h"
33 34 35

#include <texteditor/plaintexteditor.h>
#include <texteditor/codeassist/iassistproposal.h>
36
#include <texteditor/convenience.h>
37 38

#include <utils/changeset.h>
39 40 41
#include <utils/fileutils.h>

#include <QtTest>
hjk's avatar
hjk committed
42
#include <QDebug>
43 44 45 46 47 48 49 50 51 52 53 54
#include <QTextDocument>
#include <QDir>

/*!
    Tests for code completion.
 */
using namespace CPlusPlus;
using namespace CppTools;
using namespace CppTools::Internal;
using namespace TextEditor;
using namespace Core;

55 56 57
namespace {
typedef QByteArray _;

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
class CompletionTestCase
{
public:
    CompletionTestCase(const QByteArray &sourceText, const QByteArray &textToInsert = QByteArray())
        : position(-1), editorWidget(0), textDocument(0), editor(0),
          cmm(CppModelManager::instance())
    {
        source = sourceText;
        position = source.indexOf('@');
        QVERIFY(position != -1);
        source[position] = ' ';

        // Write source to file
        const QString fileName = QDir::tempPath() + QLatin1String("/file.h");
        Utils::FileSaver srcSaver(fileName);
        srcSaver.write(source);
        srcSaver.finalize();

        // Open in editor
        editor = EditorManager::openEditor(fileName);
        QVERIFY(editor);
        editorWidget = qobject_cast<TextEditor::BaseTextEditorWidget *>(editor->widget());
        QVERIFY(editorWidget);

        textDocument = editorWidget->document();

        // Get Document
        while (!cmm->snapshot().contains(fileName))
            QCoreApplication::processEvents();
        Document::Ptr document = cmm->snapshot().document(fileName);

        snapshot.insert(document);

        if (!textToInsert.isEmpty())
            insertText(textToInsert);
    }
94

95 96
    ~CompletionTestCase()
    {
97
        EditorManager::closeEditor(editor, /*askAboutModifiedEditors=*/ false);
98 99 100
        cmm->GC();
        QVERIFY(cmm->snapshot().isEmpty());
    }
101

102 103 104 105 106
    QStringList getCompletions(bool *replaceAccessOperator = 0) const
    {
        QStringList completions;
        CppCompletionAssistInterface *ai
            = new CppCompletionAssistInterface(editorWidget->document(), position,
107
                                               editorWidget->baseTextDocument()->filePath(),
108 109 110 111 112 113 114 115 116 117 118 119 120
                                               ExplicitlyInvoked, snapshot,
                                               QStringList(), QStringList());
        CppCompletionAssistProcessor processor;
        IAssistProposal *proposal = processor.perform(ai);
        if (!proposal)
            return completions;
        IAssistProposalModel *model = proposal->model();
        if (!model)
            return completions;
        CppAssistProposalModel *listmodel = dynamic_cast<CppAssistProposalModel *>(model);
        if (!listmodel)
            return completions;

121 122 123 124 125
        const int pos = proposal->basePosition();
        const int length = position - pos;
        const QString prefix = Convenience::textAt(QTextCursor(editorWidget->document()), pos, length);
        if (!prefix.isEmpty())
            listmodel->filter(prefix);
126 127
        if (listmodel->isSortable(prefix))
            listmodel->sort(prefix);
128

129 130 131 132 133
        for (int i = 0; i < listmodel->size(); ++i)
            completions << listmodel->text(i);

        if (replaceAccessOperator)
            *replaceAccessOperator = listmodel->m_replaceDotForArrow;
134

135 136
        return completions;
    }
137

138 139 140 141 142 143 144 145
    void insertText(const QByteArray &text)
    {
        Utils::ChangeSet change;
        change.insert(position, QLatin1String(text));
        QTextCursor cursor(textDocument);
        change.apply(&cursor);
        position += text.length();
    }
146

147 148 149 150 151 152 153
private:
    QByteArray source;
    int position;
    Snapshot snapshot;
    BaseTextEditorWidget *editorWidget;
    QTextDocument *textDocument;
    IEditor *editor;
154

155 156
    CppModelManager *cmm;
};
157

158 159
} // namespace

160 161
void CppToolsPlugin::test_completion_forward_declarations_present()
{
162 163 164 165 166 167 168 169 170 171 172 173
    const QByteArray source =
        "class Foo\n"
        "{\n"
        "    struct Bar;\n"
        "    int i;\n"
        "};\n"
        "\n"
        "struct Foo::Bar \n"
        "{\n"
        "    Bar() {}\n"
        "};\n"
        "\n"
174
        "@\n";
175
    CompletionTestCase test(source, "Foo::Bar::");
176 177

    QStringList expected;
178
    expected.append(QLatin1String("Bar"));
179

180
    const QStringList completions = test.getCompletions();
181 182 183
    QCOMPARE(completions, expected);
}

184 185
void CppToolsPlugin::test_completion_inside_parentheses_c_style_conversion()
{
186
    const QByteArray source =
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
            "class Base\n"
            "{\n"
            "    int i_base;\n"
            "};\n"
            "\n"
            "class Derived : public Base\n"
            "{\n"
            "    int i_derived;\n"
            "};\n"
            "\n"
            "void fun()\n"
            "{\n"
            "    Base *b = new Derived;\n"
            "    if (1)\n"
            "        @\n"
            "}\n"
            ;
204
    CompletionTestCase test(source, "((Derived *)b)->");
205

206
    const QStringList completions = test.getCompletions();
207 208 209 210 211 212 213 214 215
    QCOMPARE(completions.size(), 4);
    QVERIFY(completions.contains(QLatin1String("Derived")));
    QVERIFY(completions.contains(QLatin1String("Base")));
    QVERIFY(completions.contains(QLatin1String("i_derived")));
    QVERIFY(completions.contains(QLatin1String("i_base")));
}

void CppToolsPlugin::test_completion_inside_parentheses_cast_operator_conversion()
{
216
    const QByteArray source =
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
            "class Base\n"
            "{\n"
            "    int i_base;\n"
            "};\n"
            "\n"
            "class Derived : public Base\n"
            "{\n"
            "    int i_derived;\n"
            "};\n"
            "\n"
            "void fun()\n"
            "{\n"
            "    Base *b = new Derived;\n"
            "    if (1)\n"
            "        @\n"
            "}\n"
            ;
234
    CompletionTestCase test(source, "(static_cast<Derived *>(b))->");
235

236
    const QStringList completions = test.getCompletions();
237 238 239 240 241 242 243
    QCOMPARE(completions.size(), 4);
    QVERIFY(completions.contains(QLatin1String("Derived")));
    QVERIFY(completions.contains(QLatin1String("Base")));
    QVERIFY(completions.contains(QLatin1String("i_derived")));
    QVERIFY(completions.contains(QLatin1String("i_base")));
}

244 245
void CppToolsPlugin::test_completion_basic_1()
{
246
    const QByteArray source =
247 248 249 250 251 252 253 254 255 256
            "class Foo\n"
            "{\n"
            "    void foo();\n"
            "    int m;\n"
            "};\n"
            "\n"
            "void func() {\n"
            "    Foo f;\n"
            "    @\n"
            "}";
257
    CompletionTestCase test(source);
258

259
    QStringList basicCompletions = test.getCompletions();
260 261 262 263 264
    QVERIFY(!basicCompletions.contains(QLatin1String("foo")));
    QVERIFY(!basicCompletions.contains(QLatin1String("m")));
    QVERIFY(basicCompletions.contains(QLatin1String("Foo")));
    QVERIFY(basicCompletions.contains(QLatin1String("func")));
    QVERIFY(basicCompletions.contains(QLatin1String("f")));
265

266
    test.insertText("f.");
267

268
    QStringList memberCompletions = test.getCompletions();
269 270 271 272
    QVERIFY(memberCompletions.contains(QLatin1String("foo")));
    QVERIFY(memberCompletions.contains(QLatin1String("m")));
    QVERIFY(!memberCompletions.contains(QLatin1String("func")));
    QVERIFY(!memberCompletions.contains(QLatin1String("f")));
273 274 275 276
}

void CppToolsPlugin::test_completion_template_1()
{
277
    const QByteArray source =
278 279 280 281 282 283 284 285 286 287 288 289
            "template <class T>\n"
            "class Foo\n"
            "{\n"
            "    typedef T Type;\n"
            "    T foo();\n"
            "    T m;\n"
            "};\n"
            "\n"
            "void func() {\n"
            "    Foo f;\n"
            "    @\n"
            "}";
290
    CompletionTestCase test(source, "Foo::");
291

292
    const QStringList completions = test.getCompletions();
293 294 295 296 297 298
    QVERIFY(completions.contains(QLatin1String("Type")));
    QVERIFY(completions.contains(QLatin1String("foo")));
    QVERIFY(completions.contains(QLatin1String("m")));
    QVERIFY(!completions.contains(QLatin1String("T")));
    QVERIFY(!completions.contains(QLatin1String("f")));
    QVERIFY(!completions.contains(QLatin1String("func")));
299
}
300

301 302
void CppToolsPlugin::test_completion_template_2()
{
303
    const QByteArray source =
304 305 306 307 308 309 310 311 312 313 314 315
            "template <class T>\n"
            "struct List\n"
            "{\n"
            "    T &at(int);\n"
            "};\n"
            "\n"
            "struct Tupple { int a; int b; };\n"
            "\n"
            "void func() {\n"
            "    List<Tupple> l;\n"
            "    @\n"
            "}";
316
    CompletionTestCase test(source, "l.at(0).");
317

318
    const QStringList completions = test.getCompletions();
319
    QCOMPARE(completions.size(), 3);
320 321 322
    QVERIFY(completions.contains(QLatin1String("Tupple")));
    QVERIFY(completions.contains(QLatin1String("a")));
    QVERIFY(completions.contains(QLatin1String("b")));
323 324 325 326
}

void CppToolsPlugin::test_completion_template_3()
{
327
    const QByteArray source =
328 329 330 331 332 333 334 335 336 337 338 339
            "template <class T>\n"
            "struct List\n"
            "{\n"
            "    T t;\n"
            "};\n"
            "\n"
            "struct Tupple { int a; int b; };\n"
            "\n"
            "void func() {\n"
            "    List<Tupple> l;\n"
            "    @\n"
            "}";
340
    CompletionTestCase test(source, "l.t.");
341

342
    const QStringList completions = test.getCompletions();
343
    QCOMPARE(completions.size(), 3);
344 345 346
    QVERIFY(completions.contains(QLatin1String("Tupple")));
    QVERIFY(completions.contains(QLatin1String("a")));
    QVERIFY(completions.contains(QLatin1String("b")));
347 348 349 350
}

void CppToolsPlugin::test_completion_template_4()
{
351
    const QByteArray source =
352 353 354 355 356 357 358 359 360 361 362 363 364
            "template <class T>\n"
            "struct List\n"
            "{\n"
            "    typedef T U;\n"
            "    U u;\n"
            "};\n"
            "\n"
            "struct Tupple { int a; int b; };\n"
            "\n"
            "void func() {\n"
            "    List<Tupple> l;\n"
            "    @\n"
            "}";
365
    CompletionTestCase test(source, "l.u.");
366

367
    const QStringList completions = test.getCompletions();
368
    QCOMPARE(completions.size(), 3);
369 370 371
    QVERIFY(completions.contains(QLatin1String("Tupple")));
    QVERIFY(completions.contains(QLatin1String("a")));
    QVERIFY(completions.contains(QLatin1String("b")));
372 373 374 375
}

void CppToolsPlugin::test_completion_template_5()
{
376
    const QByteArray source =
377 378 379 380 381 382 383 384 385 386 387 388 389
            "template <class T>\n"
            "struct List\n"
            "{\n"
            "    T u;\n"
            "};\n"
            "\n"
            "struct Tupple { int a; int b; };\n"
            "\n"
            "void func() {\n"
            "    typedef List<Tupple> LT;\n"
            "    LT l;"
            "    @\n"
            "}";
390
    CompletionTestCase test(source, "l.u.");
391

392
    const QStringList completions = test.getCompletions();
393
    QCOMPARE(completions.size(), 3);
394 395 396
    QVERIFY(completions.contains(QLatin1String("Tupple")));
    QVERIFY(completions.contains(QLatin1String("a")));
    QVERIFY(completions.contains(QLatin1String("b")));
397 398
}

399 400
void CppToolsPlugin::test_completion_template_6()
{
401
    const QByteArray source =
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
            "class Item\n"
            "{\n"
            "    int i;\n"
            "};\n"
            "\n"
            "template <typename T>\n"
            "class Container\n"
            "{\n"
            "    T get();\n"
            "};\n"
            "\n"
            "template <typename T> class Container;\n"
            "\n"
            "class ItemContainer: public Container<Item>\n"
            "{};\n"
            "ItemContainer container;\n"
            "@\n"
            ;
420
    CompletionTestCase test(source, "container.get().");
421

422
    const QStringList completions = test.getCompletions();
423
    QCOMPARE(completions.size(), 2);
424 425
    QVERIFY(completions.contains(QLatin1String("Item")));
    QVERIFY(completions.contains(QLatin1String("i")));
426 427
}

428 429
void CppToolsPlugin::test_completion_template_7()
{
430
    const QByteArray source =
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
            "struct Test\n"
            "{\n"
            "   int i;\n"
            "};\n"
            "\n"
            "template<typename T>\n"
            "struct TemplateClass\n"
            "{\n"
            "    T* ptr;\n"
            "\n"
            "    typedef T element_type;\n"
            "    TemplateClass(T* t) : ptr(t) {}\n"
            "    element_type* operator->()\n"
            "    {\n"
            "        return ptr;\n"
            "    }\n"
            "};\n"
            "\n"
            "TemplateClass<Test> p(new Test);\n"
            "@\n"
            ;
452
    CompletionTestCase test(source, "p->");
453

454
    const QStringList completions = test.getCompletions();
455 456 457 458 459
    QCOMPARE(completions.size(), 2);
    QVERIFY(completions.contains(QLatin1String("Test")));
    QVERIFY(completions.contains(QLatin1String("i")));
}

460 461
void CppToolsPlugin::test_completion_type_of_pointer_is_typedef()
{
462
    const QByteArray source =
463 464 465 466 467 468 469
            "typedef struct Foo\n"
            "{\n"
            "    int foo;\n"
            "} Foo;\n"
            "Foo *bar;\n"
            "@\n"
            ;
470
    CompletionTestCase test(source, "bar->");
471

472
    const QStringList completions = test.getCompletions();
473 474 475 476 477
    QCOMPARE(completions.size(), 2);
    QVERIFY(completions.contains(QLatin1String("Foo")));
    QVERIFY(completions.contains(QLatin1String("foo")));
}

478 479
void CppToolsPlugin::test_completion_instantiate_full_specialization()
{
480
    const QByteArray source =
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
            "template<typename T>\n"
            "struct Template\n"
            "{\n"
            "   int templateT_i;\n"
            "};\n"
            "\n"
            "template<>\n"
            "struct Template<char>\n"
            "{\n"
            "    int templateChar_i;\n"
            "};\n"
            "\n"
            "Template<char> templateChar;\n"
            "@\n"
            ;
496
    CompletionTestCase test(source, "templateChar.");
497

498
    const QStringList completions = test.getCompletions();
499 500 501 502 503
    QCOMPARE(completions.size(), 2);
    QVERIFY(completions.contains(QLatin1String("Template")));
    QVERIFY(completions.contains(QLatin1String("templateChar_i")));
}

504
void CppToolsPlugin::test_completion()
505 506
{
    QFETCH(QByteArray, code);
507
    QFETCH(QByteArray, prefix);
508 509
    QFETCH(QStringList, expectedCompletions);

510
    CompletionTestCase test(code, prefix);
511

512
    QStringList actualCompletions = test.getCompletions();
513 514 515 516 517 518
    actualCompletions.sort();
    expectedCompletions.sort();

    QCOMPARE(actualCompletions, expectedCompletions);
}

519 520 521 522 523
void CppToolsPlugin::test_completion_template_as_base()
{
    test_completion();
}

524 525 526
void CppToolsPlugin::test_completion_template_as_base_data()
{
    QTest::addColumn<QByteArray>("code");
527
    QTest::addColumn<QByteArray>("prefix");
528 529 530 531 532
    QTest::addColumn<QStringList>("expectedCompletions");

    QByteArray code;
    QStringList completions;

533
    code =
534 535 536 537 538 539 540
            "class Data { int dataMember; };\n"
            "template <class T> class Other : public T { int otherMember; };\n"
            "\n"
            "void func() {\n"
            "    Other<Data> c;\n"
            "    @\n"
            "}";
541 542 543 544
    completions.append(QLatin1String("Data"));
    completions.append(QLatin1String("dataMember"));
    completions.append(QLatin1String("Other"));
    completions.append(QLatin1String("otherMember"));
545
    QTest::newRow("case: base as template directly") << code << _("c.") << completions;
546 547

    completions.clear();
548
    code =
549 550 551 552 553 554 555 556
            "class Data { int dataMember; };\n"
            "template <class T> class Other : public T { int otherMember; };\n"
            "template <class T> class More : public Other<T> { int moreMember; };\n"
            "\n"
            "void func() {\n"
            "    More<Data> c;\n"
            "    @\n"
            "}";
557 558 559 560 561 562
    completions.append(QLatin1String("Data"));
    completions.append(QLatin1String("dataMember"));
    completions.append(QLatin1String("Other"));
    completions.append(QLatin1String("otherMember"));
    completions.append(QLatin1String("More"));
    completions.append(QLatin1String("moreMember"));
563
    QTest::newRow("case: base as class template") << code << _("c.") << completions;
564 565

    completions.clear();
566
    code =
567 568 569 570 571 572 573 574
            "class Data { int dataMember; };\n"
            "template <class T> class Other : public T { int otherMember; };\n"
            "template <class T> class More : public ::Other<T> { int moreMember; };\n"
            "\n"
            "void func() {\n"
            "    More<Data> c;\n"
            "    @\n"
            "}";
575 576 577 578 579 580
    completions.append(QLatin1String("Data"));
    completions.append(QLatin1String("dataMember"));
    completions.append(QLatin1String("Other"));
    completions.append(QLatin1String("otherMember"));
    completions.append(QLatin1String("More"));
    completions.append(QLatin1String("moreMember"));
581 582
    QTest::newRow("case: base as globally qualified class template")
            << code << _("c.") << completions;
583 584

    completions.clear();
585
    code =
586 587 588 589 590 591 592 593 594 595
            "class Data { int dataMember; };\n"
            "namespace NS {\n"
            "template <class T> class Other : public T { int otherMember; };\n"
            "}\n"
            "template <class T> class More : public NS::Other<T> { int moreMember; };\n"
            "\n"
            "void func() {\n"
            "    More<Data> c;\n"
            "    @\n"
            "}";
596 597 598 599 600 601
    completions.append(QLatin1String("Data"));
    completions.append(QLatin1String("dataMember"));
    completions.append(QLatin1String("Other"));
    completions.append(QLatin1String("otherMember"));
    completions.append(QLatin1String("More"));
    completions.append(QLatin1String("moreMember"));
602 603
    QTest::newRow("case: base as namespace qualified class template")
            << code << _("c.") << completions;
604 605

    completions.clear();
606
    code =
607 608 609 610 611 612 613 614 615 616
            "class Data { int dataMember; };\n"
            "namespace NS {\n"
            "template <class T> class Delegate { typedef Data<T> Type; };\n"
            "}\n"
            "template <class T> class Final : public NS::Delegate<T>::Type { int finalMember; };\n"
            "\n"
            "void func() {\n"
            "    Final<Data> c;\n"
            "    @\n"
            "}";
617 618 619 620
    completions.append(QLatin1String("Data"));
    completions.append(QLatin1String("dataMember"));
    completions.append(QLatin1String("Final"));
    completions.append(QLatin1String("finalMember"));
621
    QTest::newRow("case: base as nested template name") << code << _("c.") << completions;
622 623

    completions.clear();
624
    code =
625 626 627 628 629 630 631 632 633 634
            "class Data { int dataMember; };\n"
            "namespace NS {\n"
            "template <class T> class Delegate { typedef Data<T> Type; };\n"
            "}\n"
            "class Final : public NS::Delegate<Data>::Type { int finalMember; };\n"
            "\n"
            "void func() {\n"
            "    Final c;\n"
            "    @\n"
            "}";
635 636 637 638
    completions.append(QLatin1String("Data"));
    completions.append(QLatin1String("dataMember"));
    completions.append(QLatin1String("Final"));
    completions.append(QLatin1String("finalMember"));
639 640
    QTest::newRow("case: base as nested template name in non-template")
            << code << _("c.") << completions;
641 642

    completions.clear();
643
    code =
644 645 646 647 648 649 650 651 652 653
            "class Data { int dataMember; };\n"
            "namespace NS {\n"
            "template <class T> class Other : public T { int otherMember; };\n"
            "}\n"
            "class Final : public NS::Other<Data> { int finalMember; };\n"
            "\n"
            "void func() {\n"
            "    Final c;\n"
            "    @\n"
            "}";
654 655 656 657 658 659
    completions.append(QLatin1String("Data"));
    completions.append(QLatin1String("dataMember"));
    completions.append(QLatin1String("Final"));
    completions.append(QLatin1String("finalMember"));
    completions.append(QLatin1String("Other"));
    completions.append(QLatin1String("otherMember"));
660
    QTest::newRow("case: base as template name in non-template") << code << _("c.") << completions;
661
}
662 663 664 665 666 667 668 669 670

void CppToolsPlugin::test_completion_use_global_identifier_as_base_class()
{
    test_completion();
}

void CppToolsPlugin::test_completion_use_global_identifier_as_base_class_data()
{
    QTest::addColumn<QByteArray>("code");
671
    QTest::addColumn<QByteArray>("prefix");
672 673 674 675 676
    QTest::addColumn<QStringList>("expectedCompletions");

    QByteArray code;
    QStringList completions;

677
    code =
678 679 680 681 682 683 684 685 686 687 688
            "struct Global\n"
            "{\n"
            "    int int_global;\n"
            "};\n"
            "\n"
            "struct Final : ::Global\n"
            "{\n"
            "   int int_final;\n"
            "};\n"
            "\n"
            "Final c;\n"
689
            "@\n";
690

691 692 693 694
    completions.append(QLatin1String("int_global"));
    completions.append(QLatin1String("int_final"));
    completions.append(QLatin1String("Final"));
    completions.append(QLatin1String("Global"));
695
    QTest::newRow("case: derived as global and base as global") << code << _("c.") << completions;
696 697 698

    completions.clear();

699
    code =
700 701 702 703 704 705 706 707 708 709 710 711 712 713
            "struct Global\n"
            "{\n"
            "    int int_global;\n"
            "};\n"
            "\n"
            "namespace NS\n"
            "{\n"
            "struct Final : ::Global\n"
            "{\n"
            "   int int_final;\n"
            "};\n"
            "}\n"
            "\n"
            "NS::Final c;\n"
714
            "@\n";
715

716 717 718 719
    completions.append(QLatin1String("int_global"));
    completions.append(QLatin1String("int_final"));
    completions.append(QLatin1String("Final"));
    completions.append(QLatin1String("Global"));
720
    QTest::newRow("case: derived is inside namespace, base as global")
721
            << code << _("c.") << completions;
722 723 724

    completions.clear();

725
    // This test does not work due to the bug QTCREATORBUG-7912
726
//    code =
727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743
//            "struct Global\n"
//            "{\n"
//            "    int int_global;\n"
//            "};\n"
//            "\n"
//            "template <typename T>\n"
//            "struct Enclosing\n"
//            "{\n"
//            "struct Final : ::Global\n"
//            "{\n"
//            "   int int_final;\n"
//            "};\n"
//            "}\n"
//            "\n"
//            "Enclosing<int>::Final c;\n"
//            "@\n"

744 745 746 747
//    completions.append(QLatin1String("int_global"));
//    completions.append(QLatin1String("int_final"));
//    completions.append(QLatin1String("Final"));
//    completions.append(QLatin1String("Global"));
748
//    QTest::newRow("case: derived is enclosed by template, base as global")
749
//    << code << _("c.") << completions;
750 751 752 753 754 755 756 757 758 759 760 761

//    completions.clear();
}

void CppToolsPlugin::test_completion_base_class_has_name_the_same_as_derived()
{
    test_completion();
}

void CppToolsPlugin::test_completion_base_class_has_name_the_same_as_derived_data()
{
    QTest::addColumn<QByteArray>("code");
762
    QTest::addColumn<QByteArray>("prefix");
763 764 765 766 767
    QTest::addColumn<QStringList>("expectedCompletions");

    QByteArray code;
    QStringList completions;

768
    code =
769 770 771 772 773 774
            "struct A : A\n"
            "{\n"
            "   int int_a;\n"
            "};\n"
            "\n"
            "A c;\n"
775
            "@\n";
776

777 778
    completions.append(QLatin1String("int_a"));
    completions.append(QLatin1String("A"));
779
    QTest::newRow("case: base class is derived class") << code << _("c.") << completions;
780 781 782

    completions.clear();

783
    code =
784 785 786 787 788 789 790 791 792
            "namespace NS\n"
            "{\n"
            "struct A : A\n"
            "{\n"
            "   int int_a;\n"
            "};\n"
            "}\n"
            "\n"
            "NS::A c;\n"
793
            "@\n";
794

795 796
    completions.append(QLatin1String("int_a"));
    completions.append(QLatin1String("A"));
797
    QTest::newRow("case: base class is derived class. class is in namespace")
798
            << code << _("c.") << completions;
799 800 801

    completions.clear();

802
    code =
803 804 805 806 807 808 809 810 811
            "namespace NS\n"
            "{\n"
            "struct A : NS::A\n"
            "{\n"
            "   int int_a;\n"
            "};\n"
            "}\n"
            "\n"
            "NS::A c;\n"
812
            "@\n";
813

814 815
    completions.append(QLatin1String("int_a"));
    completions.append(QLatin1String("A"));
816
    QTest::newRow("case: base class is derived class. class is in namespace. "
817
                  "use scope operator for base class") << code << _("c.") << completions;
818 819 820

    completions.clear();

821
    code =
822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837
            "namespace NS1\n"
            "{\n"
            "struct A\n"
            "{\n"
            "   int int_ns1_a;\n"
            "};\n"
            "}\n"
            "namespace NS2\n"
            "{\n"
            "struct A : NS1::A\n"
            "{\n"
            "   int int_ns2_a;\n"
            "};\n"
            "}\n"
            "\n"
            "NS2::A c;\n"
838
            "@\n";
839

840 841 842
    completions.append(QLatin1String("int_ns1_a"));
    completions.append(QLatin1String("int_ns2_a"));
    completions.append(QLatin1String("A"));
843
    QTest::newRow("case: base class has the same name as derived but in different namespace")
844
            << code << _("c.") << completions;
845 846 847

    completions.clear();

848
    code =
849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864
            "struct Enclosing\n"
            "{\n"
            "struct A\n"
            "{\n"
            "   int int_enclosing_a;\n"
            "};\n"
            "};\n"
            "namespace NS2\n"
            "{\n"
            "struct A : Enclosing::A\n"
            "{\n"
            "   int int_ns2_a;\n"
            "};\n"
            "}\n"
            "\n"
            "NS2::A c;\n"
865
            "@\n";
866

867 868 869
    completions.append(QLatin1String("int_enclosing_a"));
    completions.append(QLatin1String("int_ns2_a"));
    completions.append(QLatin1String("A"));
870
    QTest::newRow("case: base class has the same name as derived(in namespace) "
871
                  "but is nested by different class") << code << _("c.") << completions;
872 873 874

    completions.clear();

875
    code =
876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891
            "struct EnclosingBase\n"
            "{\n"
            "struct A\n"
            "{\n"
            "   int int_enclosing_base_a;\n"
            "};\n"
            "};\n"
            "struct EnclosingDerived\n"
            "{\n"
            "struct A : EnclosingBase::A\n"
            "{\n"
            "   int int_enclosing_derived_a;\n"
            "};\n"
            "};\n"
            "\n"
            "EnclosingDerived::A c;\n"
892
            "@\n";
893

894 895 896
    completions.append(QLatin1String("int_enclosing_base_a"));
    completions.append(QLatin1String("int_enclosing_derived_a"));
    completions.append(QLatin1String("A"));
897
    QTest::newRow("case: base class has the same name as derived(nested) "
898
                  "but is nested by different class") << code << _("c.") << completions;
899 900 901

    completions.clear();

902
    code =
903 904 905 906 907 908 909
            "template <typename T>\n"
            "struct A : A\n"
            "{\n"
            "   int int_a;\n"
            "};\n"
            "\n"
            "A<int> c;\n"
910
            "@\n";
911

912 913
    completions.append(QLatin1String("int_a"));
    completions.append(QLatin1String("A"));
914
    QTest::newRow("case: base class is derived class. class is a template")
915
            << code << _("c.") << completions;
916 917 918

    completions.clear();
}
919 920 921 922 923 924 925 926 927

void CppToolsPlugin::test_completion_cyclic_inheritance()
{
    test_completion();
}

void CppToolsPlugin::test_completion_cyclic_inheritance_data()
{
    QTest::addColumn<QByteArray>("code");
928
    QTest::addColumn<QByteArray>("prefix");
929 930 931 932 933
    QTest::addColumn<QStringList>("expectedCompletions");

    QByteArray code;
    QStringList completions;

934
    code =
935 936 937 938 939 940 941
            "struct B;\n"
            "struct A : B { int _a; };\n"
            "struct B : A { int _b; };\n"
            "\n"
            "A c;\n"
            "@\n"
            ;
942 943 944 945
    completions.append(QLatin1String("A"));
    completions.append(QLatin1String("_a"));
    completions.append(QLatin1String("B"));
    completions.append(QLatin1String("_b"));
946
    QTest::newRow("case: direct cyclic inheritance") << code << _("c.") << completions;
947 948

    completions.clear();
949
    code =
950 951 952 953 954 955 956 957
            "struct C;\n"
            "struct A : C { int _a; };\n"
            "struct B : A { int _b; };\n"
            "struct C : B { int _c; };\n"
            "\n"
            "A c;\n"
            "@\n"
            ;
958 959 960 961 962 963
    completions.append(QLatin1String("A"));
    completions.append(QLatin1String("_a"));
    completions.append(QLatin1String("B"));
    completions.append(QLatin1String("_b"));
    completions.append(QLatin1String("C"));
    completions.append(QLatin1String("_c"));
964
    QTest::newRow("case: indirect cyclic inheritance") << code << _("c.") << completions;
965 966

    completions.clear();
967
    code =
968 969 970 971 972 973 974 975
            "struct B;\n"
            "struct A : B { int _a; };\n"
            "struct C { int _c; };\n"
            "struct B : C, A { int _b; };\n"
            "\n"
            "A c;\n"
            "@\n"
            ;
976 977 978 979 980 981
    completions.append(QLatin1String("A"));
    completions.append(QLatin1String("_a"));
    completions.append(QLatin1String("B"));
    completions.append(QLatin1String("_b"));
    completions.append(QLatin1String("C"));
    completions.append(QLatin1String("_c"));
982
    QTest::newRow("case: indirect cyclic inheritance") << code << _("c.") << completions;
983 984

    completions.clear();
985
    code =
986 987 988 989 990 991 992 993 994 995 996 997 998 999
            "template< typename T > struct C;\n"
            "template< typename T, typename S > struct D : C< S >\n"
            "{\n"
            "   T _d_t;\n"
            "   S _d_s;\n"
            "};\n"
            "template< typename T > struct C : D< T, int >\n"
            "{\n"
            "   T _c_t;\n"
            "};\n"
            "\n"
            "D<int, float> c;\n"
            "@\n"
            ;
1000 1001 1002 1003 1004
    completions.append(QLatin1String("D"));
    completions.append(QLatin1String("_d_t"));
    completions.append(QLatin1String("_d_s"));
    completions.append(QLatin1String("C"));
    completions.append(QLatin1String("_c_t"));
1005
    QTest::newRow("case: direct cyclic inheritance with templates")
1006
            << code << _("c.") << completions;
1007 1008

    completions.clear();
1009
    code =
1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027
            "template< typename T > struct C;\n"
            "template< typename T, typename S > struct D : C< S >\n"
            "{\n"
            "   T _d_t;\n"
            "   S _d_s;\n"
            "};\n"
            "template< typename T > struct B : D< T, int >\n"
            "{\n"
            "   T _b_t;\n"
            "};\n"
            "template< typename T > struct C : B<T>\n"
            "{\n"
            "   T _c_t;\n"
            "};\n"
            "\n"
            "D<int, float> c;\n"
            "@\n"
            ;
1028 1029 1030 1031 1032 1033 1034
    completions.append(QLatin1String("D"));
    completions.append(QLatin1String("_d_t"));
    completions.append(QLatin1String("_d_s"));
    completions.append(QLatin1String("C"));
    completions.append(QLatin1String("_c_t"));
    completions.append(QLatin1String("B"));
    completions.append(QLatin1String("_b_t"));
1035
    QTest::newRow("case: indirect cyclic inheritance with templates")
1036
            << code << _("c.") << completions;
1037

1038
    completions.clear();
1039
    code =
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067
           "namespace NS\n"
           "{\n"
           "template <typename T> struct SuperClass\n"
           "{\n"
           "    typedef T Type;\n"
           "    Type super_class_type;\n"
           "};\n"
           "}\n"
           "\n"
           "template <typename T>\n"
           "struct Class;\n"
           "\n"
           "template <typename T, typename S>\n"
           "struct ClassRecurse : Class<S>\n"
           "{\n"
           "    T class_recurse_t;\n"
           "    S class_recurse_s;\n"
           "};\n"
           "\n"
           "template <typename T>\n"
           "struct Class : ClassRecurse< T, typename ::NS::SuperClass<T>::Type >\n"
           "{\n"
           "    T class_t;\n"
           "};\n"
           "\n"
           "Class<int> c;\n"
           "@\n"
            ;
1068 1069 1070 1071 1072
    completions.append(QLatin1String("Class"));
    completions.append(QLatin1String("ClassRecurse"));
    completions.append(QLatin1String("class_t"));
    completions.append(QLatin1String("class_recurse_s"));
    completions.append(QLatin1String("class_recurse_t"));
1073
    QTest::newRow("case: direct cyclic inheritance with templates, more complex situation")
1074
            << code << _("c.") << completions;
1075
}
1076

1077 1078 1079 1080 1081
void CppToolsPlugin::test_completion_template_function()
{
    QFETCH(QByteArray, code);
    QFETCH(QStringList, expectedCompletions);

1082
    CompletionTestCase test(code);
1083

1084
    QStringList actualCompletions = test.getCompletions();
1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102
    actualCompletions.sort();
    expectedCompletions.sort();

    QString errorPattern(QLatin1String("Completion not found: %1"));
    foreach (const QString &completion, expectedCompletions) {
        QByteArray errorMessage = errorPattern.arg(completion).toUtf8();
        QVERIFY2(actualCompletions.contains(completion), errorMessage.data());
    }
}

void CppToolsPlugin::test_completion_template_function_data()
{
    QTest::addColumn<QByteArray>("code");
    QTest::addColumn<QStringList>("expectedCompletions");

    QByteArray code;
    QStringList completions;

1103
    code =
1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118
           "template <class tclass, typename tname, int tint>\n"
           "tname Hello(const tclass &e)\n"
           "{\n"
           "    tname e2 = e;\n"
           "    @\n"
           "}";

    completions.append(QLatin1String("tclass"));
    completions.append(QLatin1String("tname"));
    completions.append(QLatin1String("tint"));
    QTest::newRow("case: template parameters in template function body")
            << code << completions;

    completions.clear();

1119
    code =
1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132
           "template <class tclass, typename tname, int tint>\n"
           "tname Hello(const tclass &e, @)\n"
           "{\n"
           "    tname e2 = e;\n"
           "}";

    completions.append(QLatin1String("tclass"));
    completions.append(QLatin1String("tname"));
    completions.append(QLatin1String("tint"));
    QTest::newRow("case: template parameters in template function parameters list")
            << code << completions;
}

1133 1134 1135 1136 1137 1138 1139