cppcodegen_test.cpp 22.8 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
Bill King's avatar
Bill King committed
2
**
Eike Ziller's avatar
Eike Ziller committed
3 4
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://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
Eike Ziller's avatar
Eike Ziller committed
12 13
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
Eike Ziller's avatar
Eike Ziller committed
14
** use the contact form at http://www.qt.io/contact-us.
Bill King's avatar
Bill King committed
15 16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
** Alternatively, this file may be used under the terms of the GNU Lesser
Eike Ziller's avatar
Eike Ziller committed
18 19 20 21 22 23
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
hjk's avatar
hjk committed
24
**
Eike Ziller's avatar
Eike Ziller committed
25 26
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
Bill King's avatar
Bill King committed
27 28
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
29
****************************************************************************/
Bill King's avatar
Bill King committed
30

31
#include "cpptoolsplugin.h"
32 33
#include "cpptoolstestcase.h"
#include "insertionpointlocator.h"
34

35
#include <utils/fileutils.h>
36
#include <utils/qtcassert.h>
37 38

#include <QtTest>
hjk's avatar
hjk committed
39
#include <QDebug>
40
#include <QDir>
41

42 43 44 45
/*!
    Tests for various parts of the code generation. Well, okay, currently it only
    tests the InsertionPointLocator.
 */
46
using namespace CPlusPlus;
47
using namespace CppTools;
48
using namespace CppTools::Internal;
49

50 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
namespace {

Document::Ptr createDocument(const QString filePath, const QByteArray text,
                             unsigned expectedGlobalSymbolCount)
{
    Document::Ptr document = Document::create(filePath);
    document->setUtf8Source(text);
    document->check();
    QTC_ASSERT(document->diagnosticMessages().isEmpty(), return Document::Ptr());
    QTC_ASSERT(document->globalSymbolCount() == expectedGlobalSymbolCount, return Document::Ptr());

    return document;
}

Document::Ptr createDocumentAndFile(Tests::TemporaryDir *temporaryDir,
                                    const QByteArray relativeFilePath,
                                    const QByteArray text,
                                    unsigned expectedGlobalSymbolCount)
{
    QTC_ASSERT(temporaryDir, return Document::Ptr());
    const QString absoluteFilePath = temporaryDir->createFile(relativeFilePath, text);
    QTC_ASSERT(!absoluteFilePath.isEmpty(), return Document::Ptr());

    return createDocument(absoluteFilePath, text, expectedGlobalSymbolCount);
}

} // anonymous namespace

78 79 80
/*!
    Should insert at line 3, column 1, with "public:\n" as prefix and without suffix.
 */
81
void CppToolsPlugin::test_codegen_public_in_empty_class()
82 83 84 85
{
    const QByteArray src = "\n"
            "class Foo\n" // line 1
            "{\n"
86
            "};\n"
87
            "\n";
88 89
    Document::Ptr doc = createDocument(QLatin1String("public_in_empty_class"), src, 1U);
    QVERIFY(doc);
90

91 92 93 94 95 96 97
    Class *foo = doc->globalSymbolAt(0)->asClass();
    QVERIFY(foo);
    QCOMPARE(foo->line(), 1U);
    QCOMPARE(foo->column(), 7U);

    Snapshot snapshot;
    snapshot.insert(doc);
98
    CppRefactoringChanges changes(snapshot);
99
    InsertionPointLocator find(changes);
100
    InsertionLocation loc = find.methodDeclarationInClass(
101 102
                doc->fileName(),
                foo,
103
                InsertionPointLocator::Public);
104
    QVERIFY(loc.isValid());
105
    QCOMPARE(loc.prefix(), QLatin1String("public:\n"));
106
    QVERIFY(loc.suffix().isEmpty());
107
    QCOMPARE(loc.line(), 3U);
108 109 110
    QCOMPARE(loc.column(), 1U);
}

111 112 113
/*!
    Should insert at line 3, column 1, without prefix and without suffix.
 */
114
void CppToolsPlugin::test_codegen_public_in_nonempty_class()
115 116 117 118
{
    const QByteArray src = "\n"
            "class Foo\n" // line 1
            "{\n"
119 120
            "public:\n"   // line 3
            "};\n"        // line 4
121
            "\n";
122 123
    Document::Ptr doc = createDocument(QLatin1String("public_in_nonempty_class"), src, 1U);
    QVERIFY(doc);
124

125 126 127 128
    Class *foo = doc->globalSymbolAt(0)->asClass();
    QVERIFY(foo);
    QCOMPARE(foo->line(), 1U);
    QCOMPARE(foo->column(), 7U);
129

130 131
    Snapshot snapshot;
    snapshot.insert(doc);
132
    CppRefactoringChanges changes(snapshot);
133
    InsertionPointLocator find(changes);
134
    InsertionLocation loc = find.methodDeclarationInClass(
135 136
                doc->fileName(),
                foo,
137
                InsertionPointLocator::Public);
138
    QVERIFY(loc.isValid());
139
    QVERIFY(loc.prefix().isEmpty());
140
    QVERIFY(loc.suffix().isEmpty());
141
    QCOMPARE(loc.line(), 4U);
142 143 144
    QCOMPARE(loc.column(), 1U);
}

145 146 147
/*!
    Should insert at line 3, column 1, with "public:\n" as prefix and "\n suffix.
 */
148
void CppToolsPlugin::test_codegen_public_before_protected()
149 150 151 152 153 154 155
{
    const QByteArray src = "\n"
            "class Foo\n"  // line 1
            "{\n"
            "protected:\n" // line 3
            "};\n"
            "\n";
156 157
    Document::Ptr doc = createDocument(QLatin1String("public_before_protected"), src, 1U);
    QVERIFY(doc);
158

159 160 161 162
    Class *foo = doc->globalSymbolAt(0)->asClass();
    QVERIFY(foo);
    QCOMPARE(foo->line(), 1U);
    QCOMPARE(foo->column(), 7U);
163

164 165
    Snapshot snapshot;
    snapshot.insert(doc);
166
    CppRefactoringChanges changes(snapshot);
167
    InsertionPointLocator find(changes);
168
    InsertionLocation loc = find.methodDeclarationInClass(
169 170
                doc->fileName(),
                foo,
171
                InsertionPointLocator::Public);
172 173 174 175 176 177 178
    QVERIFY(loc.isValid());
    QCOMPARE(loc.prefix(), QLatin1String("public:\n"));
    QCOMPARE(loc.suffix(), QLatin1String("\n"));
    QCOMPARE(loc.column(), 1U);
    QCOMPARE(loc.line(), 3U);
}

179 180 181 182
/*!
    Should insert at line 4, column 1, with "private:\n" as prefix and without
    suffix.
 */
183
void CppToolsPlugin::test_codegen_private_after_protected()
184 185 186 187 188 189 190
{
    const QByteArray src = "\n"
            "class Foo\n"  // line 1
            "{\n"
            "protected:\n" // line 3
            "};\n"
            "\n";
191 192
    Document::Ptr doc = createDocument(QLatin1String("private_after_protected"), src, 1U);
    QVERIFY(doc);
193

194 195 196 197
    Class *foo = doc->globalSymbolAt(0)->asClass();
    QVERIFY(foo);
    QCOMPARE(foo->line(), 1U);
    QCOMPARE(foo->column(), 7U);
198

199 200
    Snapshot snapshot;
    snapshot.insert(doc);
201
    CppRefactoringChanges changes(snapshot);
202
    InsertionPointLocator find(changes);
203
    InsertionLocation loc = find.methodDeclarationInClass(
204 205
                doc->fileName(),
                foo,
206
                InsertionPointLocator::Private);
207 208 209 210 211 212 213
    QVERIFY(loc.isValid());
    QCOMPARE(loc.prefix(), QLatin1String("private:\n"));
    QVERIFY(loc.suffix().isEmpty());
    QCOMPARE(loc.column(), 1U);
    QCOMPARE(loc.line(), 4U);
}

214 215 216 217
/*!
    Should insert at line 4, column 1, with "protected:\n" as prefix and without
    suffix.
 */
218
void CppToolsPlugin::test_codegen_protected_in_nonempty_class()
219 220 221 222 223 224 225
{
    const QByteArray src = "\n"
            "class Foo\n" // line 1
            "{\n"
            "public:\n"   // line 3
            "};\n"        // line 4
            "\n";
226 227
    Document::Ptr doc = createDocument(QLatin1String("protected_in_nonempty_class"), src, 1U);
    QVERIFY(doc);
228

229 230 231 232
    Class *foo = doc->globalSymbolAt(0)->asClass();
    QVERIFY(foo);
    QCOMPARE(foo->line(), 1U);
    QCOMPARE(foo->column(), 7U);
233

234 235
    Snapshot snapshot;
    snapshot.insert(doc);
236
    CppRefactoringChanges changes(snapshot);
237
    InsertionPointLocator find(changes);
238
    InsertionLocation loc = find.methodDeclarationInClass(
239 240
                doc->fileName(),
                foo,
241
                InsertionPointLocator::Protected);
242 243 244 245 246 247 248
    QVERIFY(loc.isValid());
    QCOMPARE(loc.prefix(), QLatin1String("protected:\n"));
    QVERIFY(loc.suffix().isEmpty());
    QCOMPARE(loc.column(), 1U);
    QCOMPARE(loc.line(), 4U);
}

249 250 251
/*!
    Should insert at line 4, column 1, with "protected\n" as prefix and "\n" suffix.
 */
252
void CppToolsPlugin::test_codegen_protected_between_public_and_private()
253 254 255 256 257 258 259 260
{
    const QByteArray src = "\n"
            "class Foo\n" // line 1
            "{\n"
            "public:\n"   // line 3
            "private:\n"  // line 4
            "};\n"        // line 5
            "\n";
261 262
    Document::Ptr doc = createDocument(QLatin1String("protected_betwee_public_and_private"), src, 1U);
    QVERIFY(doc);
263

264 265 266 267
    Class *foo = doc->globalSymbolAt(0)->asClass();
    QVERIFY(foo);
    QCOMPARE(foo->line(), 1U);
    QCOMPARE(foo->column(), 7U);
268

269 270
    Snapshot snapshot;
    snapshot.insert(doc);
271
    CppRefactoringChanges changes(snapshot);
272
    InsertionPointLocator find(changes);
273
    InsertionLocation loc = find.methodDeclarationInClass(
274 275
                doc->fileName(),
                foo,
276
                InsertionPointLocator::Protected);
277 278 279 280 281 282 283
    QVERIFY(loc.isValid());
    QCOMPARE(loc.prefix(), QLatin1String("protected:\n"));
    QCOMPARE(loc.suffix(), QLatin1String("\n"));
    QCOMPARE(loc.column(), 1U);
    QCOMPARE(loc.line(), 4U);
}

284 285 286 287 288 289 290
/*!
    Should insert at line 18, column 1, with "private slots:\n" as prefix and "\n"
    as suffix.

    This is the typical Qt Designer case, with test-input like what the integration
    generates.
 */
291
void CppToolsPlugin::test_codegen_qtdesigner_integration()
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
{
    const QByteArray src = "/**** Some long (C)opyright notice ****/\n"
            "#ifndef MAINWINDOW_H\n"
            "#define MAINWINDOW_H\n"
            "\n"
            "#include <QMainWindow>\n"
            "\n"
            "namespace Ui {\n"
            "    class MainWindow;\n"
            "}\n"
            "\n"
            "class MainWindow : public QMainWindow\n" // line 10
            "{\n"
            "    Q_OBJECT\n"
            "\n"
            "public:\n" // line 14
            "    explicit MainWindow(QWidget *parent = 0);\n"
            "    ~MainWindow();\n"
            "\n"
            "private:\n" // line 18
            "    Ui::MainWindow *ui;\n"
            "};\n"
            "\n"
            "#endif // MAINWINDOW_H\n";

317 318
    Document::Ptr doc = createDocument(QLatin1String("qtdesigner_integration"), src, 2U);
    QVERIFY(doc);
319

320 321 322 323
    Class *foo = doc->globalSymbolAt(1)->asClass();
    QVERIFY(foo);
    QCOMPARE(foo->line(), 10U);
    QCOMPARE(foo->column(), 7U);
324

325 326
    Snapshot snapshot;
    snapshot.insert(doc);
327
    CppRefactoringChanges changes(snapshot);
328
    InsertionPointLocator find(changes);
329
    InsertionLocation loc = find.methodDeclarationInClass(
330 331
                doc->fileName(),
                foo,
332
                InsertionPointLocator::PrivateSlot);
333 334 335 336 337 338 339
    QVERIFY(loc.isValid());
    QCOMPARE(loc.prefix(), QLatin1String("private slots:\n"));
    QCOMPARE(loc.suffix(), QLatin1String("\n"));
    QCOMPARE(loc.line(), 18U);
    QCOMPARE(loc.column(), 1U);
}

340
void CppToolsPlugin::test_codegen_definition_empty_class()
341
{
342 343 344 345
    Tests::TemporaryDir temporaryDir;
    QVERIFY(temporaryDir.isValid());

    const QByteArray headerText = "\n"
346 347 348 349 350
            "class Foo\n"  // line 1
            "{\n"
            "void foo();\n" // line 3
            "};\n"
            "\n";
351 352
    Document::Ptr headerDocument = createDocumentAndFile(&temporaryDir, "file.h", headerText, 1U);
    QVERIFY(headerDocument);
353

354
    const QByteArray sourceText = "\n"
355 356
            "int x;\n"  // line 1
            "\n";
357 358
    Document::Ptr sourceDocument = createDocumentAndFile(&temporaryDir, "file.cpp", sourceText, 1U);
    QVERIFY(sourceDocument);
359 360

    Snapshot snapshot;
361 362
    snapshot.insert(headerDocument);
    snapshot.insert(sourceDocument);
363

364
    Class *foo = headerDocument->globalSymbolAt(0)->asClass();
365 366 367 368 369 370 371 372 373 374 375 376 377 378
    QVERIFY(foo);
    QCOMPARE(foo->line(), 1U);
    QCOMPARE(foo->column(), 7U);
    QCOMPARE(foo->memberCount(), 1U);
    Declaration *decl = foo->memberAt(0)->asDeclaration();
    QVERIFY(decl);
    QCOMPARE(decl->line(), 3U);
    QCOMPARE(decl->column(), 6U);

    CppRefactoringChanges changes(snapshot);
    InsertionPointLocator find(changes);
    QList<InsertionLocation> locList = find.methodDefinition(decl);
    QVERIFY(locList.size() == 1);
    InsertionLocation loc = locList.first();
379
    QCOMPARE(loc.fileName(), sourceDocument->fileName());
380 381
    QCOMPARE(loc.prefix(), QLatin1String("\n\n"));
    QCOMPARE(loc.suffix(), QString());
Leandro Melo's avatar
Leandro Melo committed
382 383
    QCOMPARE(loc.line(), 3U);
    QCOMPARE(loc.column(), 1U);
384 385
}

386
void CppToolsPlugin::test_codegen_definition_first_member()
387
{
388 389 390 391
    Tests::TemporaryDir temporaryDir;
    QVERIFY(temporaryDir.isValid());

    const QByteArray headerText = "\n"
392 393 394 395 396 397
            "class Foo\n"  // line 1
            "{\n"
            "void foo();\n" // line 3
            "void bar();\n" // line 4
            "};\n"
            "\n";
398 399
    Document::Ptr headerDocument = createDocumentAndFile(&temporaryDir, "file.h", headerText, 1U);
    QVERIFY(headerDocument);
400

401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
    const QByteArray sourceText = QString::fromLatin1(
            "\n"
            "#include \"%1/file.h\"\n" // line 1
            "int x;\n"
            "\n"
            "void Foo::bar()\n" // line 4
            "{\n"
            "\n"
            "}\n"
            "\n"
            "int y;\n").arg(temporaryDir.path()).toLatin1();
    Document::Ptr sourceDocument = createDocumentAndFile(&temporaryDir, "file.cpp", sourceText, 3U);
    QVERIFY(sourceDocument);
    sourceDocument->addIncludeFile(Document::Include(QLatin1String("file.h"),
                                                     headerDocument->fileName(), 1,
                                                     Client::IncludeLocal));
417 418

    Snapshot snapshot;
419 420
    snapshot.insert(headerDocument);
    snapshot.insert(sourceDocument);
421

422
    Class *foo = headerDocument->globalSymbolAt(0)->asClass();
423 424 425 426 427 428 429 430 431 432 433 434 435 436
    QVERIFY(foo);
    QCOMPARE(foo->line(), 1U);
    QCOMPARE(foo->column(), 7U);
    QCOMPARE(foo->memberCount(), 2U);
    Declaration *decl = foo->memberAt(0)->asDeclaration();
    QVERIFY(decl);
    QCOMPARE(decl->line(), 3U);
    QCOMPARE(decl->column(), 6U);

    CppRefactoringChanges changes(snapshot);
    InsertionPointLocator find(changes);
    QList<InsertionLocation> locList = find.methodDefinition(decl);
    QVERIFY(locList.size() == 1);
    InsertionLocation loc = locList.first();
437
    QCOMPARE(loc.fileName(), sourceDocument->fileName());
438 439 440 441 442 443
    QCOMPARE(loc.line(), 4U);
    QCOMPARE(loc.column(), 1U);
    QCOMPARE(loc.suffix(), QLatin1String("\n\n"));
    QCOMPARE(loc.prefix(), QString());
}

444
void CppToolsPlugin::test_codegen_definition_last_member()
445
{
446 447 448 449
    Tests::TemporaryDir temporaryDir;
    QVERIFY(temporaryDir.isValid());

    const QByteArray headerText = "\n"
450 451 452 453 454 455
            "class Foo\n"  // line 1
            "{\n"
            "void foo();\n" // line 3
            "void bar();\n" // line 4
            "};\n"
            "\n";
456 457
    Document::Ptr headerDocument = createDocumentAndFile(&temporaryDir, "file.h", headerText, 1U);
    QVERIFY(headerDocument);
458

459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
    const QByteArray sourceText = QString::fromLatin1(
            "\n"
            "#include \"%1/file.h\"\n" // line 1
            "int x;\n"
            "\n"
            "void Foo::foo()\n" // line 4
            "{\n"
            "\n"
            "}\n" // line 7
            "\n"
            "int y;\n").arg(temporaryDir.path()).toLatin1();

    Document::Ptr sourceDocument = createDocumentAndFile(&temporaryDir, "file.cpp", sourceText, 3U);
    QVERIFY(sourceDocument);
    sourceDocument->addIncludeFile(Document::Include(QLatin1String("file.h"),
                                                     headerDocument->fileName(), 1,
                                                     Client::IncludeLocal));
476 477

    Snapshot snapshot;
478 479
    snapshot.insert(headerDocument);
    snapshot.insert(sourceDocument);
480

481
    Class *foo = headerDocument->globalSymbolAt(0)->asClass();
482 483 484 485 486 487 488 489 490 491 492 493 494 495
    QVERIFY(foo);
    QCOMPARE(foo->line(), 1U);
    QCOMPARE(foo->column(), 7U);
    QCOMPARE(foo->memberCount(), 2U);
    Declaration *decl = foo->memberAt(1)->asDeclaration();
    QVERIFY(decl);
    QCOMPARE(decl->line(), 4U);
    QCOMPARE(decl->column(), 6U);

    CppRefactoringChanges changes(snapshot);
    InsertionPointLocator find(changes);
    QList<InsertionLocation> locList = find.methodDefinition(decl);
    QVERIFY(locList.size() == 1);
    InsertionLocation loc = locList.first();
496
    QCOMPARE(loc.fileName(), sourceDocument->fileName());
497 498 499 500 501 502
    QCOMPARE(loc.line(), 7U);
    QCOMPARE(loc.column(), 2U);
    QCOMPARE(loc.prefix(), QLatin1String("\n\n"));
    QCOMPARE(loc.suffix(), QString());
}

503
void CppToolsPlugin::test_codegen_definition_middle_member()
504
{
505 506 507 508
    Tests::TemporaryDir temporaryDir;
    QVERIFY(temporaryDir.isValid());

    const QByteArray headerText = "\n"
509 510 511 512 513 514 515 516
            "class Foo\n"  // line 1
            "{\n"
            "void foo();\n" // line 3
            "void bar();\n" // line 4
            "void car();\n" // line 5
            "};\n"
            "\n";

517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
    Document::Ptr headerDocument = createDocumentAndFile(&temporaryDir, "file.h", headerText, 1U);
    QVERIFY(headerDocument);

    const QByteArray sourceText = QString::fromLatin1(
            "\n"
            "#include \"%1/file.h\"\n" // line 1
            "int x;\n"
            "\n"
            "void Foo::foo()\n" // line 4
            "{\n"
            "\n"
            "}\n" // line 7
            "\n"
            "void Foo::car()\n" // line 9
            "{\n"
            "\n"
            "}\n"
            "\n"
            "int y;\n").arg(QDir::tempPath()).toLatin1();

    Document::Ptr sourceDocument = createDocumentAndFile(&temporaryDir, "file.cpp", sourceText, 4U);
    QVERIFY(sourceDocument);
    sourceDocument->addIncludeFile(Document::Include(QLatin1String("file.h"),
                                                     headerDocument->fileName(), 1,
                                                     Client::IncludeLocal));
542 543

    Snapshot snapshot;
544 545
    snapshot.insert(headerDocument);
    snapshot.insert(sourceDocument);
546

547
    Class *foo = headerDocument->globalSymbolAt(0)->asClass();
548 549 550 551 552 553 554 555 556 557 558 559 560 561
    QVERIFY(foo);
    QCOMPARE(foo->line(), 1U);
    QCOMPARE(foo->column(), 7U);
    QCOMPARE(foo->memberCount(), 3U);
    Declaration *decl = foo->memberAt(1)->asDeclaration();
    QVERIFY(decl);
    QCOMPARE(decl->line(), 4U);
    QCOMPARE(decl->column(), 6U);

    CppRefactoringChanges changes(snapshot);
    InsertionPointLocator find(changes);
    QList<InsertionLocation> locList = find.methodDefinition(decl);
    QVERIFY(locList.size() == 1);
    InsertionLocation loc = locList.first();
562
    QCOMPARE(loc.fileName(), sourceDocument->fileName());
563 564 565 566 567
    QCOMPARE(loc.line(), 7U);
    QCOMPARE(loc.column(), 2U);
    QCOMPARE(loc.prefix(), QLatin1String("\n\n"));
    QCOMPARE(loc.suffix(), QString());
}
568 569 570

void CppToolsPlugin::test_codegen_definition_middle_member_surrounded_by_undefined()
{
571 572 573 574
    Tests::TemporaryDir temporaryDir;
    QVERIFY(temporaryDir.isValid());

    const QByteArray headerText = "\n"
575 576 577 578 579 580 581 582
            "class Foo\n"  // line 1
            "{\n"
            "void foo();\n" // line 3
            "void bar();\n" // line 4
            "void baz();\n" // line 5
            "void car();\n" // line 6
            "};\n"
            "\n";
583 584
    Document::Ptr headerDocument = createDocumentAndFile(&temporaryDir, "file.h", headerText, 1U);
    QVERIFY(headerDocument);
585

586
    const QByteArray sourceText = QString::fromLatin1(
587 588 589 590 591 592 593 594 595
            "\n"
            "#include \"%1/file.h\"\n" // line 1
            "int x;\n"
            "\n"
            "void Foo::car()\n" // line 4
            "{\n"
            "\n"
            "}\n"
            "\n"
596 597 598 599 600 601
            "int y;\n").arg(temporaryDir.path()).toLatin1();
    Document::Ptr sourceDocument = createDocumentAndFile(&temporaryDir, "file.cpp", sourceText, 3U);
    QVERIFY(sourceDocument);
    sourceDocument->addIncludeFile(Document::Include(QLatin1String("file.h"),
                                                     headerDocument->fileName(), 1,
                                                     Client::IncludeLocal));
602 603

    Snapshot snapshot;
604 605
    snapshot.insert(headerDocument);
    snapshot.insert(sourceDocument);
606

607
    Class *foo = headerDocument->globalSymbolAt(0)->asClass();
608 609 610 611 612 613 614 615 616 617 618 619 620 621
    QVERIFY(foo);
    QCOMPARE(foo->line(), 1U);
    QCOMPARE(foo->column(), 7U);
    QCOMPARE(foo->memberCount(), 4U);
    Declaration *decl = foo->memberAt(1)->asDeclaration();
    QVERIFY(decl);
    QCOMPARE(decl->line(), 4U);
    QCOMPARE(decl->column(), 6U);

    CppRefactoringChanges changes(snapshot);
    InsertionPointLocator find(changes);
    QList<InsertionLocation> locList = find.methodDefinition(decl);
    QVERIFY(locList.size() == 1);
    InsertionLocation loc = locList.first();
622
    QCOMPARE(loc.fileName(), sourceDocument->fileName());
623 624 625 626 627 628 629 630
    QCOMPARE(loc.line(), 4U);
    QCOMPARE(loc.column(), 1U);
    QCOMPARE(loc.prefix(), QString());
    QCOMPARE(loc.suffix(), QLatin1String("\n\n"));
}

void CppToolsPlugin::test_codegen_definition_member_specific_file()
{
631 632 633 634
    Tests::TemporaryDir temporaryDir;
    QVERIFY(temporaryDir.isValid());

    const QByteArray headerText = "\n"
635 636 637 638 639 640 641 642 643 644 645
            "class Foo\n"  // line 1
            "{\n"
            "void foo();\n" // line 3
            "void bar();\n" // line 4
            "void baz();\n" // line 5
            "};\n"
            "\n"
            "void Foo::bar()\n"
            "{\n"
            "\n"
            "}\n";
646 647
    Document::Ptr headerDocument = createDocumentAndFile(&temporaryDir, "file.h", headerText, 2U);
    QVERIFY(headerDocument);
648

649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
    const QByteArray sourceText = QString::fromLatin1(
            "\n"
            "#include \"%1/file.h\"\n" // line 1
            "int x;\n"
            "\n"
            "void Foo::foo()\n" // line 4
            "{\n"
            "\n"
            "}\n" // line 7
            "\n"
            "int y;\n").arg(temporaryDir.path()).toLatin1();
    Document::Ptr sourceDocument = createDocumentAndFile(&temporaryDir, "file.cpp", sourceText, 3U);
    QVERIFY(sourceDocument);
    sourceDocument->addIncludeFile(Document::Include(QLatin1String("file.h"),
                                                     headerDocument->fileName(), 1,
                                                     Client::IncludeLocal));
665 666

    Snapshot snapshot;
667 668
    snapshot.insert(headerDocument);
    snapshot.insert(sourceDocument);
669

670
    Class *foo = headerDocument->globalSymbolAt(0)->asClass();
671 672 673 674 675 676 677 678 679 680 681
    QVERIFY(foo);
    QCOMPARE(foo->line(), 1U);
    QCOMPARE(foo->column(), 7U);
    QCOMPARE(foo->memberCount(), 3U);
    Declaration *decl = foo->memberAt(2)->asDeclaration();
    QVERIFY(decl);
    QCOMPARE(decl->line(), 5U);
    QCOMPARE(decl->column(), 6U);

    CppRefactoringChanges changes(snapshot);
    InsertionPointLocator find(changes);
682
    QList<InsertionLocation> locList = find.methodDefinition(decl, true, sourceDocument->fileName());
683 684
    QVERIFY(locList.size() == 1);
    InsertionLocation loc = locList.first();
685
    QCOMPARE(loc.fileName(), sourceDocument->fileName());
686 687 688 689 690
    QCOMPARE(loc.line(), 7U);
    QCOMPARE(loc.column(), 2U);
    QCOMPARE(loc.prefix(), QLatin1String("\n\n"));
    QCOMPARE(loc.suffix(), QString());
}