1 //===- unittests/libclang/LibclangTest.cpp --- libclang tests -------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "TestUtils.h" 10 #include "clang-c/Index.h" 11 #include "clang-c/Rewrite.h" 12 #include "llvm/ADT/StringRef.h" 13 #include "llvm/Support/Debug.h" 14 #include "llvm/Support/FileSystem.h" 15 #include "llvm/Support/Path.h" 16 #include "llvm/Support/raw_ostream.h" 17 #include "gtest/gtest.h" 18 #include <cstring> 19 #include <fstream> 20 #include <functional> 21 #include <map> 22 #include <memory> 23 #include <optional> 24 #include <set> 25 #define DEBUG_TYPE "libclang-test" 26 27 TEST(libclang, clang_parseTranslationUnit2_InvalidArgs) { 28 EXPECT_EQ(CXError_InvalidArguments, 29 clang_parseTranslationUnit2(nullptr, nullptr, nullptr, 0, nullptr, 30 0, 0, nullptr)); 31 } 32 33 TEST(libclang, clang_createTranslationUnit_InvalidArgs) { 34 EXPECT_EQ(nullptr, clang_createTranslationUnit(nullptr, nullptr)); 35 } 36 37 TEST(libclang, clang_createTranslationUnit2_InvalidArgs) { 38 EXPECT_EQ(CXError_InvalidArguments, 39 clang_createTranslationUnit2(nullptr, nullptr, nullptr)); 40 41 CXTranslationUnit TU = reinterpret_cast<CXTranslationUnit>(1); 42 EXPECT_EQ(CXError_InvalidArguments, 43 clang_createTranslationUnit2(nullptr, nullptr, &TU)); 44 EXPECT_EQ(nullptr, TU); 45 } 46 47 namespace { 48 struct TestVFO { 49 const char *Contents; 50 CXVirtualFileOverlay VFO; 51 52 TestVFO(const char *Contents) : Contents(Contents) { 53 VFO = clang_VirtualFileOverlay_create(0); 54 } 55 56 void map(const char *VPath, const char *RPath) { 57 CXErrorCode Err = clang_VirtualFileOverlay_addFileMapping(VFO, VPath, RPath); 58 EXPECT_EQ(Err, CXError_Success); 59 } 60 61 void mapError(const char *VPath, const char *RPath, CXErrorCode ExpErr) { 62 CXErrorCode Err = clang_VirtualFileOverlay_addFileMapping(VFO, VPath, RPath); 63 EXPECT_EQ(Err, ExpErr); 64 } 65 66 ~TestVFO() { 67 if (Contents) { 68 char *BufPtr; 69 unsigned BufSize; 70 clang_VirtualFileOverlay_writeToBuffer(VFO, 0, &BufPtr, &BufSize); 71 std::string BufStr(BufPtr, BufSize); 72 EXPECT_STREQ(Contents, BufStr.c_str()); 73 clang_free(BufPtr); 74 } 75 clang_VirtualFileOverlay_dispose(VFO); 76 } 77 }; 78 } 79 80 TEST(libclang, VirtualFileOverlay_Basic) { 81 const char *contents = 82 "{\n" 83 " 'version': 0,\n" 84 " 'roots': [\n" 85 " {\n" 86 " 'type': 'directory',\n" 87 " 'name': \"/path/virtual\",\n" 88 " 'contents': [\n" 89 " {\n" 90 " 'type': 'file',\n" 91 " 'name': \"foo.h\",\n" 92 " 'external-contents': \"/real/foo.h\"\n" 93 " }\n" 94 " ]\n" 95 " }\n" 96 " ]\n" 97 "}\n"; 98 TestVFO T(contents); 99 T.map("/path/virtual/foo.h", "/real/foo.h"); 100 } 101 102 TEST(libclang, VirtualFileOverlay_Unicode) { 103 const char *contents = 104 "{\n" 105 " 'version': 0,\n" 106 " 'roots': [\n" 107 " {\n" 108 " 'type': 'directory',\n" 109 " 'name': \"/path/\\u266B\",\n" 110 " 'contents': [\n" 111 " {\n" 112 " 'type': 'file',\n" 113 " 'name': \"\\u2602.h\",\n" 114 " 'external-contents': \"/real/\\u2602.h\"\n" 115 " }\n" 116 " ]\n" 117 " }\n" 118 " ]\n" 119 "}\n"; 120 TestVFO T(contents); 121 T.map("/path/♫/☂.h", "/real/☂.h"); 122 } 123 124 TEST(libclang, VirtualFileOverlay_InvalidArgs) { 125 TestVFO T(nullptr); 126 T.mapError("/path/./virtual/../foo.h", "/real/foo.h", 127 CXError_InvalidArguments); 128 } 129 130 TEST(libclang, VirtualFileOverlay_RemapDirectories) { 131 const char *contents = 132 "{\n" 133 " 'version': 0,\n" 134 " 'roots': [\n" 135 " {\n" 136 " 'type': 'directory',\n" 137 " 'name': \"/another/dir\",\n" 138 " 'contents': [\n" 139 " {\n" 140 " 'type': 'file',\n" 141 " 'name': \"foo2.h\",\n" 142 " 'external-contents': \"/real/foo2.h\"\n" 143 " }\n" 144 " ]\n" 145 " },\n" 146 " {\n" 147 " 'type': 'directory',\n" 148 " 'name': \"/path/virtual/dir\",\n" 149 " 'contents': [\n" 150 " {\n" 151 " 'type': 'file',\n" 152 " 'name': \"foo1.h\",\n" 153 " 'external-contents': \"/real/foo1.h\"\n" 154 " },\n" 155 " {\n" 156 " 'type': 'file',\n" 157 " 'name': \"foo3.h\",\n" 158 " 'external-contents': \"/real/foo3.h\"\n" 159 " },\n" 160 " {\n" 161 " 'type': 'directory',\n" 162 " 'name': \"in/subdir\",\n" 163 " 'contents': [\n" 164 " {\n" 165 " 'type': 'file',\n" 166 " 'name': \"foo4.h\",\n" 167 " 'external-contents': \"/real/foo4.h\"\n" 168 " }\n" 169 " ]\n" 170 " }\n" 171 " ]\n" 172 " }\n" 173 " ]\n" 174 "}\n"; 175 TestVFO T(contents); 176 T.map("/path/virtual/dir/foo1.h", "/real/foo1.h"); 177 T.map("/another/dir/foo2.h", "/real/foo2.h"); 178 T.map("/path/virtual/dir/foo3.h", "/real/foo3.h"); 179 T.map("/path/virtual/dir/in/subdir/foo4.h", "/real/foo4.h"); 180 } 181 182 TEST(libclang, VirtualFileOverlay_CaseInsensitive) { 183 const char *contents = 184 "{\n" 185 " 'version': 0,\n" 186 " 'case-sensitive': 'false',\n" 187 " 'roots': [\n" 188 " {\n" 189 " 'type': 'directory',\n" 190 " 'name': \"/path/virtual\",\n" 191 " 'contents': [\n" 192 " {\n" 193 " 'type': 'file',\n" 194 " 'name': \"foo.h\",\n" 195 " 'external-contents': \"/real/foo.h\"\n" 196 " }\n" 197 " ]\n" 198 " }\n" 199 " ]\n" 200 "}\n"; 201 TestVFO T(contents); 202 T.map("/path/virtual/foo.h", "/real/foo.h"); 203 clang_VirtualFileOverlay_setCaseSensitivity(T.VFO, false); 204 } 205 206 TEST(libclang, VirtualFileOverlay_SharedPrefix) { 207 const char *contents = 208 "{\n" 209 " 'version': 0,\n" 210 " 'roots': [\n" 211 " {\n" 212 " 'type': 'directory',\n" 213 " 'name': \"/path/foo\",\n" 214 " 'contents': [\n" 215 " {\n" 216 " 'type': 'file',\n" 217 " 'name': \"bar\",\n" 218 " 'external-contents': \"/real/bar\"\n" 219 " },\n" 220 " {\n" 221 " 'type': 'file',\n" 222 " 'name': \"bar.h\",\n" 223 " 'external-contents': \"/real/bar.h\"\n" 224 " }\n" 225 " ]\n" 226 " },\n" 227 " {\n" 228 " 'type': 'directory',\n" 229 " 'name': \"/path/foobar\",\n" 230 " 'contents': [\n" 231 " {\n" 232 " 'type': 'file',\n" 233 " 'name': \"baz.h\",\n" 234 " 'external-contents': \"/real/baz.h\"\n" 235 " }\n" 236 " ]\n" 237 " },\n" 238 " {\n" 239 " 'type': 'directory',\n" 240 " 'name': \"/path\",\n" 241 " 'contents': [\n" 242 " {\n" 243 " 'type': 'file',\n" 244 " 'name': \"foobarbaz.h\",\n" 245 " 'external-contents': \"/real/foobarbaz.h\"\n" 246 " }\n" 247 " ]\n" 248 " }\n" 249 " ]\n" 250 "}\n"; 251 TestVFO T(contents); 252 T.map("/path/foo/bar.h", "/real/bar.h"); 253 T.map("/path/foo/bar", "/real/bar"); 254 T.map("/path/foobar/baz.h", "/real/baz.h"); 255 T.map("/path/foobarbaz.h", "/real/foobarbaz.h"); 256 } 257 258 TEST(libclang, VirtualFileOverlay_AdjacentDirectory) { 259 const char *contents = 260 "{\n" 261 " 'version': 0,\n" 262 " 'roots': [\n" 263 " {\n" 264 " 'type': 'directory',\n" 265 " 'name': \"/path/dir1\",\n" 266 " 'contents': [\n" 267 " {\n" 268 " 'type': 'file',\n" 269 " 'name': \"foo.h\",\n" 270 " 'external-contents': \"/real/foo.h\"\n" 271 " },\n" 272 " {\n" 273 " 'type': 'directory',\n" 274 " 'name': \"subdir\",\n" 275 " 'contents': [\n" 276 " {\n" 277 " 'type': 'file',\n" 278 " 'name': \"bar.h\",\n" 279 " 'external-contents': \"/real/bar.h\"\n" 280 " }\n" 281 " ]\n" 282 " }\n" 283 " ]\n" 284 " },\n" 285 " {\n" 286 " 'type': 'directory',\n" 287 " 'name': \"/path/dir2\",\n" 288 " 'contents': [\n" 289 " {\n" 290 " 'type': 'file',\n" 291 " 'name': \"baz.h\",\n" 292 " 'external-contents': \"/real/baz.h\"\n" 293 " }\n" 294 " ]\n" 295 " }\n" 296 " ]\n" 297 "}\n"; 298 TestVFO T(contents); 299 T.map("/path/dir1/foo.h", "/real/foo.h"); 300 T.map("/path/dir1/subdir/bar.h", "/real/bar.h"); 301 T.map("/path/dir2/baz.h", "/real/baz.h"); 302 } 303 304 TEST(libclang, VirtualFileOverlay_TopLevel) { 305 const char *contents = 306 "{\n" 307 " 'version': 0,\n" 308 " 'roots': [\n" 309 " {\n" 310 " 'type': 'directory',\n" 311 " 'name': \"/\",\n" 312 " 'contents': [\n" 313 " {\n" 314 " 'type': 'file',\n" 315 " 'name': \"foo.h\",\n" 316 " 'external-contents': \"/real/foo.h\"\n" 317 " }\n" 318 " ]\n" 319 " }\n" 320 " ]\n" 321 "}\n"; 322 TestVFO T(contents); 323 T.map("/foo.h", "/real/foo.h"); 324 } 325 326 TEST(libclang, VirtualFileOverlay_Empty) { 327 const char *contents = 328 "{\n" 329 " 'version': 0,\n" 330 " 'roots': [\n" 331 " ]\n" 332 "}\n"; 333 TestVFO T(contents); 334 } 335 336 TEST(libclang, ModuleMapDescriptor) { 337 const char *Contents = 338 "framework module TestFrame {\n" 339 " umbrella header \"TestFrame.h\"\n" 340 "\n" 341 " export *\n" 342 " module * { export * }\n" 343 "}\n"; 344 345 CXModuleMapDescriptor MMD = clang_ModuleMapDescriptor_create(0); 346 347 clang_ModuleMapDescriptor_setFrameworkModuleName(MMD, "TestFrame"); 348 clang_ModuleMapDescriptor_setUmbrellaHeader(MMD, "TestFrame.h"); 349 350 char *BufPtr; 351 unsigned BufSize; 352 clang_ModuleMapDescriptor_writeToBuffer(MMD, 0, &BufPtr, &BufSize); 353 std::string BufStr(BufPtr, BufSize); 354 EXPECT_STREQ(Contents, BufStr.c_str()); 355 clang_free(BufPtr); 356 clang_ModuleMapDescriptor_dispose(MMD); 357 } 358 359 TEST_F(LibclangParseTest, GlobalOptions) { 360 EXPECT_EQ(clang_CXIndex_getGlobalOptions(Index), CXGlobalOpt_None); 361 } 362 363 class LibclangIndexOptionsTest : public LibclangParseTest { 364 virtual void AdjustOptions(CXIndexOptions &Opts) {} 365 366 protected: 367 void CreateIndex() override { 368 CXIndexOptions Opts; 369 memset(&Opts, 0, sizeof(Opts)); 370 Opts.Size = sizeof(CXIndexOptions); 371 AdjustOptions(Opts); 372 Index = clang_createIndexWithOptions(&Opts); 373 ASSERT_TRUE(Index); 374 } 375 }; 376 377 TEST_F(LibclangIndexOptionsTest, GlobalOptions) { 378 EXPECT_EQ(clang_CXIndex_getGlobalOptions(Index), CXGlobalOpt_None); 379 } 380 381 class LibclangIndexingEnabledIndexOptionsTest 382 : public LibclangIndexOptionsTest { 383 void AdjustOptions(CXIndexOptions &Opts) override { 384 Opts.ThreadBackgroundPriorityForIndexing = CXChoice_Enabled; 385 } 386 }; 387 388 TEST_F(LibclangIndexingEnabledIndexOptionsTest, GlobalOptions) { 389 EXPECT_EQ(clang_CXIndex_getGlobalOptions(Index), 390 CXGlobalOpt_ThreadBackgroundPriorityForIndexing); 391 } 392 393 class LibclangIndexingDisabledEditingEnabledIndexOptionsTest 394 : public LibclangIndexOptionsTest { 395 void AdjustOptions(CXIndexOptions &Opts) override { 396 Opts.ThreadBackgroundPriorityForIndexing = CXChoice_Disabled; 397 Opts.ThreadBackgroundPriorityForEditing = CXChoice_Enabled; 398 } 399 }; 400 401 TEST_F(LibclangIndexingDisabledEditingEnabledIndexOptionsTest, GlobalOptions) { 402 EXPECT_EQ(clang_CXIndex_getGlobalOptions(Index), 403 CXGlobalOpt_ThreadBackgroundPriorityForEditing); 404 } 405 406 class LibclangBothEnabledIndexOptionsTest : public LibclangIndexOptionsTest { 407 void AdjustOptions(CXIndexOptions &Opts) override { 408 Opts.ThreadBackgroundPriorityForIndexing = CXChoice_Enabled; 409 Opts.ThreadBackgroundPriorityForEditing = CXChoice_Enabled; 410 } 411 }; 412 413 TEST_F(LibclangBothEnabledIndexOptionsTest, GlobalOptions) { 414 EXPECT_EQ(clang_CXIndex_getGlobalOptions(Index), 415 CXGlobalOpt_ThreadBackgroundPriorityForAll); 416 } 417 418 class LibclangPreambleStorageTest : public LibclangParseTest { 419 std::string Main = "main.cpp"; 420 421 protected: 422 std::string PreambleDir; 423 void InitializePreambleDir() { 424 llvm::SmallString<128> PathBuffer(TestDir); 425 llvm::sys::path::append(PathBuffer, "preambles"); 426 namespace fs = llvm::sys::fs; 427 ASSERT_FALSE(fs::create_directory(PathBuffer, false, fs::perms::owner_all)); 428 429 PreambleDir = static_cast<std::string>(PathBuffer); 430 FilesAndDirsToRemove.insert(PreambleDir); 431 } 432 433 public: 434 void CountPreamblesInPreambleDir(int PreambleCount) { 435 // For some reason, the preamble is not created without '\n' before `int`. 436 WriteFile(Main, "\nint main() {}"); 437 438 TUFlags |= CXTranslationUnit_CreatePreambleOnFirstParse; 439 ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, 440 nullptr, 0, TUFlags); 441 442 int FileCount = 0; 443 444 namespace fs = llvm::sys::fs; 445 std::error_code EC; 446 for (fs::directory_iterator File(PreambleDir, EC), FileEnd; 447 File != FileEnd && !EC; File.increment(EC)) { 448 ++FileCount; 449 450 EXPECT_EQ(File->type(), fs::file_type::regular_file); 451 452 const auto Filename = llvm::sys::path::filename(File->path()); 453 EXPECT_EQ(Filename.size(), std::strlen("preamble-%%%%%%.pch")); 454 EXPECT_TRUE(Filename.startswith("preamble-")); 455 EXPECT_TRUE(Filename.endswith(".pch")); 456 457 const auto Status = File->status(); 458 ASSERT_TRUE(Status); 459 if (false) { 460 // The permissions assertion below fails, because the .pch.tmp file is 461 // created with default permissions and replaces the .pch file along 462 // with its permissions. Therefore the permissions set in 463 // TempPCHFile::create() don't matter in the end. 464 EXPECT_EQ(Status->permissions(), fs::owner_read | fs::owner_write); 465 } 466 } 467 468 EXPECT_EQ(FileCount, PreambleCount); 469 } 470 }; 471 472 class LibclangNotOverriddenPreambleStoragePathTest 473 : public LibclangPreambleStorageTest { 474 protected: 475 void CreateIndex() override { 476 InitializePreambleDir(); 477 LibclangPreambleStorageTest::CreateIndex(); 478 } 479 }; 480 481 class LibclangSetPreambleStoragePathTest : public LibclangPreambleStorageTest { 482 virtual const char *PreambleStoragePath() = 0; 483 484 protected: 485 void CreateIndex() override { 486 InitializePreambleDir(); 487 488 CXIndexOptions Opts{}; 489 Opts.Size = sizeof(CXIndexOptions); 490 Opts.PreambleStoragePath = PreambleStoragePath(); 491 Index = clang_createIndexWithOptions(&Opts); 492 ASSERT_TRUE(Index); 493 } 494 }; 495 496 class LibclangNullPreambleStoragePathTest 497 : public LibclangSetPreambleStoragePathTest { 498 const char *PreambleStoragePath() override { return nullptr; } 499 }; 500 class LibclangEmptyPreambleStoragePathTest 501 : public LibclangSetPreambleStoragePathTest { 502 const char *PreambleStoragePath() override { return ""; } 503 }; 504 class LibclangPreambleDirPreambleStoragePathTest 505 : public LibclangSetPreambleStoragePathTest { 506 const char *PreambleStoragePath() override { return PreambleDir.c_str(); } 507 }; 508 509 TEST_F(LibclangNotOverriddenPreambleStoragePathTest, CountPreambles) { 510 CountPreamblesInPreambleDir(0); 511 } 512 TEST_F(LibclangNullPreambleStoragePathTest, CountPreambles) { 513 CountPreamblesInPreambleDir(0); 514 } 515 TEST_F(LibclangEmptyPreambleStoragePathTest, CountPreambles) { 516 CountPreamblesInPreambleDir(0); 517 } 518 TEST_F(LibclangPreambleDirPreambleStoragePathTest, CountPreambles) { 519 CountPreamblesInPreambleDir(1); 520 } 521 522 TEST_F(LibclangParseTest, AllSkippedRanges) { 523 std::string Header = "header.h", Main = "main.cpp"; 524 WriteFile(Header, 525 "#ifdef MANGOS\n" 526 "printf(\"mmm\");\n" 527 "#endif"); 528 WriteFile(Main, 529 "#include \"header.h\"\n" 530 "#ifdef KIWIS\n" 531 "printf(\"mmm!!\");\n" 532 "#endif"); 533 534 ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, 535 nullptr, 0, TUFlags); 536 537 CXSourceRangeList *Ranges = clang_getAllSkippedRanges(ClangTU); 538 EXPECT_EQ(2U, Ranges->count); 539 540 CXSourceLocation cxl; 541 unsigned line; 542 cxl = clang_getRangeStart(Ranges->ranges[0]); 543 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 544 EXPECT_EQ(1U, line); 545 cxl = clang_getRangeEnd(Ranges->ranges[0]); 546 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 547 EXPECT_EQ(3U, line); 548 549 cxl = clang_getRangeStart(Ranges->ranges[1]); 550 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 551 EXPECT_EQ(2U, line); 552 cxl = clang_getRangeEnd(Ranges->ranges[1]); 553 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 554 EXPECT_EQ(4U, line); 555 556 clang_disposeSourceRangeList(Ranges); 557 } 558 559 TEST_F(LibclangParseTest, EvaluateChildExpression) { 560 std::string Main = "main.m"; 561 WriteFile(Main, "#define kFOO @\"foo\"\n" 562 "void foobar(void) {\n" 563 " {kFOO;}\n" 564 "}\n"); 565 ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, nullptr, 566 0, TUFlags); 567 568 CXCursor C = clang_getTranslationUnitCursor(ClangTU); 569 clang_visitChildren( 570 C, 571 [](CXCursor cursor, CXCursor parent, 572 CXClientData client_data) -> CXChildVisitResult { 573 if (clang_getCursorKind(cursor) == CXCursor_FunctionDecl) { 574 int numberedStmt = 0; 575 clang_visitChildren( 576 cursor, 577 [](CXCursor cursor, CXCursor parent, 578 CXClientData client_data) -> CXChildVisitResult { 579 int &numberedStmt = *((int *)client_data); 580 if (clang_getCursorKind(cursor) == CXCursor_CompoundStmt) { 581 if (numberedStmt) { 582 CXEvalResult RE = clang_Cursor_Evaluate(cursor); 583 EXPECT_NE(RE, nullptr); 584 EXPECT_EQ(clang_EvalResult_getKind(RE), 585 CXEval_ObjCStrLiteral); 586 clang_EvalResult_dispose(RE); 587 return CXChildVisit_Break; 588 } 589 numberedStmt++; 590 } 591 return CXChildVisit_Recurse; 592 }, 593 &numberedStmt); 594 EXPECT_EQ(numberedStmt, 1); 595 } 596 return CXChildVisit_Continue; 597 }, 598 nullptr); 599 } 600 601 class LibclangReparseTest : public LibclangParseTest { 602 public: 603 void DisplayDiagnostics() { 604 unsigned NumDiagnostics = clang_getNumDiagnostics(ClangTU); 605 for (unsigned i = 0; i < NumDiagnostics; ++i) { 606 auto Diag = clang_getDiagnostic(ClangTU, i); 607 LLVM_DEBUG(llvm::dbgs() 608 << clang_getCString(clang_formatDiagnostic( 609 Diag, clang_defaultDiagnosticDisplayOptions())) 610 << "\n"); 611 clang_disposeDiagnostic(Diag); 612 } 613 } 614 bool ReparseTU(unsigned num_unsaved_files, CXUnsavedFile* unsaved_files) { 615 if (clang_reparseTranslationUnit(ClangTU, num_unsaved_files, unsaved_files, 616 clang_defaultReparseOptions(ClangTU))) { 617 LLVM_DEBUG(llvm::dbgs() << "Reparse failed\n"); 618 return false; 619 } 620 DisplayDiagnostics(); 621 return true; 622 } 623 }; 624 625 TEST_F(LibclangReparseTest, FileName) { 626 std::string CppName = "main.cpp"; 627 WriteFile(CppName, "int main() {}"); 628 ClangTU = clang_parseTranslationUnit(Index, CppName.c_str(), nullptr, 0, 629 nullptr, 0, TUFlags); 630 CXFile cxf = clang_getFile(ClangTU, CppName.c_str()); 631 632 CXString cxname = clang_getFileName(cxf); 633 ASSERT_STREQ(clang_getCString(cxname), CppName.c_str()); 634 clang_disposeString(cxname); 635 636 cxname = clang_File_tryGetRealPathName(cxf); 637 ASSERT_TRUE(llvm::StringRef(clang_getCString(cxname)).endswith("main.cpp")); 638 clang_disposeString(cxname); 639 } 640 641 TEST_F(LibclangReparseTest, Reparse) { 642 const char *HeaderTop = "#ifndef H\n#define H\nstruct Foo { int bar;"; 643 const char *HeaderBottom = "\n};\n#endif\n"; 644 const char *CppFile = "#include \"HeaderFile.h\"\nint main() {" 645 " Foo foo; foo.bar = 7; foo.baz = 8; }\n"; 646 std::string HeaderName = "HeaderFile.h"; 647 std::string CppName = "CppFile.cpp"; 648 WriteFile(CppName, CppFile); 649 WriteFile(HeaderName, std::string(HeaderTop) + HeaderBottom); 650 651 ClangTU = clang_parseTranslationUnit(Index, CppName.c_str(), nullptr, 0, 652 nullptr, 0, TUFlags); 653 EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU)); 654 DisplayDiagnostics(); 655 656 // Immedaitely reparse. 657 ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */)); 658 EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU)); 659 660 std::string NewHeaderContents = 661 std::string(HeaderTop) + "int baz;" + HeaderBottom; 662 WriteFile(HeaderName, NewHeaderContents); 663 664 // Reparse after fix. 665 ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */)); 666 EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU)); 667 } 668 669 TEST_F(LibclangReparseTest, ReparseWithModule) { 670 const char *HeaderTop = "#ifndef H\n#define H\nstruct Foo { int bar;"; 671 const char *HeaderBottom = "\n};\n#endif\n"; 672 const char *MFile = "#include \"HeaderFile.h\"\nint main() {" 673 " struct Foo foo; foo.bar = 7; foo.baz = 8; }\n"; 674 const char *ModFile = "module A { header \"HeaderFile.h\" }\n"; 675 std::string HeaderName = "HeaderFile.h"; 676 std::string MName = "MFile.m"; 677 std::string ModName = "module.modulemap"; 678 WriteFile(MName, MFile); 679 WriteFile(HeaderName, std::string(HeaderTop) + HeaderBottom); 680 WriteFile(ModName, ModFile); 681 682 // Removing recursively is necessary to delete the module cache. 683 RemoveTestDirRecursivelyDuringTeardown = true; 684 std::string ModulesCache = std::string("-fmodules-cache-path=") + TestDir; 685 const char *Args[] = { "-fmodules", ModulesCache.c_str(), 686 "-I", TestDir.c_str() }; 687 int NumArgs = std::size(Args); 688 ClangTU = clang_parseTranslationUnit(Index, MName.c_str(), Args, NumArgs, 689 nullptr, 0, TUFlags); 690 EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU)); 691 DisplayDiagnostics(); 692 693 // Immedaitely reparse. 694 ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */)); 695 EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU)); 696 697 std::string NewHeaderContents = 698 std::string(HeaderTop) + "int baz;" + HeaderBottom; 699 WriteFile(HeaderName, NewHeaderContents); 700 701 // Reparse after fix. 702 ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */)); 703 EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU)); 704 } 705 706 TEST_F(LibclangReparseTest, clang_parseTranslationUnit2FullArgv) { 707 // Provide a fake GCC 99.9.9 standard library that always overrides any local 708 // GCC installation. 709 std::string EmptyFiles[] = {"lib/gcc/arm-linux-gnueabi/99.9.9/crtbegin.o", 710 "include/arm-linux-gnueabi/.keep", 711 "include/c++/99.9.9/vector"}; 712 713 for (auto &Name : EmptyFiles) 714 WriteFile(Name, "\n"); 715 716 std::string Filename = "test.cc"; 717 WriteFile(Filename, "#include <vector>\n"); 718 719 std::string Clang = "bin/clang"; 720 WriteFile(Clang, ""); 721 722 const char *Argv[] = {Clang.c_str(), "-target", "arm-linux-gnueabi", 723 "-stdlib=libstdc++", "--gcc-toolchain="}; 724 725 EXPECT_EQ(CXError_Success, 726 clang_parseTranslationUnit2FullArgv(Index, Filename.c_str(), Argv, 727 std::size(Argv), 728 nullptr, 0, TUFlags, &ClangTU)); 729 EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU)); 730 DisplayDiagnostics(); 731 } 732 733 class LibclangPrintingPolicyTest : public LibclangParseTest { 734 public: 735 CXPrintingPolicy Policy = nullptr; 736 737 void SetUp() override { 738 LibclangParseTest::SetUp(); 739 std::string File = "file.cpp"; 740 WriteFile(File, "int i;\n"); 741 ClangTU = clang_parseTranslationUnit(Index, File.c_str(), nullptr, 0, 742 nullptr, 0, TUFlags); 743 CXCursor TUCursor = clang_getTranslationUnitCursor(ClangTU); 744 Policy = clang_getCursorPrintingPolicy(TUCursor); 745 } 746 void TearDown() override { 747 clang_PrintingPolicy_dispose(Policy); 748 LibclangParseTest::TearDown(); 749 } 750 }; 751 752 TEST_F(LibclangPrintingPolicyTest, SetAndGetProperties) { 753 for (unsigned Value = 0; Value < 2; ++Value) { 754 for (int I = 0; I < CXPrintingPolicy_LastProperty; ++I) { 755 auto Property = static_cast<enum CXPrintingPolicyProperty>(I); 756 757 clang_PrintingPolicy_setProperty(Policy, Property, Value); 758 EXPECT_EQ(Value, clang_PrintingPolicy_getProperty(Policy, Property)); 759 } 760 } 761 } 762 763 TEST_F(LibclangReparseTest, PreprocessorSkippedRanges) { 764 std::string Header = "header.h", Main = "main.cpp"; 765 WriteFile(Header, 766 "#ifdef MANGOS\n" 767 "printf(\"mmm\");\n" 768 "#endif"); 769 WriteFile(Main, 770 "#include \"header.h\"\n" 771 "#ifdef GUAVA\n" 772 "#endif\n" 773 "#ifdef KIWIS\n" 774 "printf(\"mmm!!\");\n" 775 "#endif"); 776 777 for (int i = 0; i != 3; ++i) { 778 unsigned flags = TUFlags | CXTranslationUnit_PrecompiledPreamble; 779 if (i == 2) 780 flags |= CXTranslationUnit_CreatePreambleOnFirstParse; 781 782 if (i != 0) 783 clang_disposeTranslationUnit(ClangTU); // dispose from previous iter 784 785 // parse once 786 ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, 787 nullptr, 0, flags); 788 if (i != 0) { 789 // reparse 790 ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */)); 791 } 792 793 // Check all ranges are there 794 CXSourceRangeList *Ranges = clang_getAllSkippedRanges(ClangTU); 795 EXPECT_EQ(3U, Ranges->count); 796 797 CXSourceLocation cxl; 798 unsigned line; 799 cxl = clang_getRangeStart(Ranges->ranges[0]); 800 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 801 EXPECT_EQ(1U, line); 802 cxl = clang_getRangeEnd(Ranges->ranges[0]); 803 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 804 EXPECT_EQ(3U, line); 805 806 cxl = clang_getRangeStart(Ranges->ranges[1]); 807 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 808 EXPECT_EQ(2U, line); 809 cxl = clang_getRangeEnd(Ranges->ranges[1]); 810 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 811 EXPECT_EQ(3U, line); 812 813 cxl = clang_getRangeStart(Ranges->ranges[2]); 814 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 815 EXPECT_EQ(4U, line); 816 cxl = clang_getRangeEnd(Ranges->ranges[2]); 817 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 818 EXPECT_EQ(6U, line); 819 820 clang_disposeSourceRangeList(Ranges); 821 822 // Check obtaining ranges by each file works 823 CXFile cxf = clang_getFile(ClangTU, Header.c_str()); 824 Ranges = clang_getSkippedRanges(ClangTU, cxf); 825 EXPECT_EQ(1U, Ranges->count); 826 cxl = clang_getRangeStart(Ranges->ranges[0]); 827 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 828 EXPECT_EQ(1U, line); 829 clang_disposeSourceRangeList(Ranges); 830 831 cxf = clang_getFile(ClangTU, Main.c_str()); 832 Ranges = clang_getSkippedRanges(ClangTU, cxf); 833 EXPECT_EQ(2U, Ranges->count); 834 cxl = clang_getRangeStart(Ranges->ranges[0]); 835 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 836 EXPECT_EQ(2U, line); 837 cxl = clang_getRangeStart(Ranges->ranges[1]); 838 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 839 EXPECT_EQ(4U, line); 840 clang_disposeSourceRangeList(Ranges); 841 } 842 } 843 844 class LibclangSerializationTest : public LibclangParseTest { 845 public: 846 bool SaveAndLoadTU(const std::string &Filename) { 847 unsigned options = clang_defaultSaveOptions(ClangTU); 848 if (clang_saveTranslationUnit(ClangTU, Filename.c_str(), options) != 849 CXSaveError_None) { 850 LLVM_DEBUG(llvm::dbgs() << "Saving failed\n"); 851 return false; 852 } 853 854 clang_disposeTranslationUnit(ClangTU); 855 856 ClangTU = clang_createTranslationUnit(Index, Filename.c_str()); 857 858 if (!ClangTU) { 859 LLVM_DEBUG(llvm::dbgs() << "Loading failed\n"); 860 return false; 861 } 862 863 return true; 864 } 865 }; 866 867 TEST_F(LibclangSerializationTest, TokenKindsAreCorrectAfterLoading) { 868 // Ensure that "class" is recognized as a keyword token after serializing 869 // and reloading the AST, as it is not a keyword for the default LangOptions. 870 std::string HeaderName = "test.h"; 871 WriteFile(HeaderName, "enum class Something {};"); 872 873 const char *Argv[] = {"-xc++-header", "-std=c++11"}; 874 875 ClangTU = clang_parseTranslationUnit(Index, HeaderName.c_str(), Argv, 876 std::size(Argv), nullptr, 877 0, TUFlags); 878 879 auto CheckTokenKinds = [=]() { 880 CXSourceRange Range = 881 clang_getCursorExtent(clang_getTranslationUnitCursor(ClangTU)); 882 883 CXToken *Tokens; 884 unsigned int NumTokens; 885 clang_tokenize(ClangTU, Range, &Tokens, &NumTokens); 886 887 ASSERT_EQ(6u, NumTokens); 888 EXPECT_EQ(CXToken_Keyword, clang_getTokenKind(Tokens[0])); 889 EXPECT_EQ(CXToken_Keyword, clang_getTokenKind(Tokens[1])); 890 EXPECT_EQ(CXToken_Identifier, clang_getTokenKind(Tokens[2])); 891 EXPECT_EQ(CXToken_Punctuation, clang_getTokenKind(Tokens[3])); 892 EXPECT_EQ(CXToken_Punctuation, clang_getTokenKind(Tokens[4])); 893 EXPECT_EQ(CXToken_Punctuation, clang_getTokenKind(Tokens[5])); 894 895 clang_disposeTokens(ClangTU, Tokens, NumTokens); 896 }; 897 898 CheckTokenKinds(); 899 900 std::string ASTName = "test.ast"; 901 WriteFile(ASTName, ""); 902 903 ASSERT_TRUE(SaveAndLoadTU(ASTName)); 904 905 CheckTokenKinds(); 906 } 907 908 TEST_F(LibclangParseTest, clang_getVarDeclInitializer) { 909 std::string Main = "main.cpp"; 910 WriteFile(Main, "int foo() { return 5; }; const int a = foo();"); 911 ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, nullptr, 912 0, TUFlags); 913 914 CXCursor C = clang_getTranslationUnitCursor(ClangTU); 915 clang_visitChildren( 916 C, 917 [](CXCursor cursor, CXCursor parent, 918 CXClientData client_data) -> CXChildVisitResult { 919 if (clang_getCursorKind(cursor) == CXCursor_VarDecl) { 920 const CXCursor Initializer = clang_Cursor_getVarDeclInitializer(cursor); 921 EXPECT_FALSE(clang_Cursor_isNull(Initializer)); 922 CXString Spelling = clang_getCursorSpelling(Initializer); 923 const char* const SpellingCSstr = clang_getCString(Spelling); 924 EXPECT_TRUE(SpellingCSstr); 925 EXPECT_EQ(std::string(SpellingCSstr), std::string("foo")); 926 clang_disposeString(Spelling); 927 return CXChildVisit_Break; 928 } 929 return CXChildVisit_Continue; 930 }, 931 nullptr); 932 } 933 934 TEST_F(LibclangParseTest, clang_hasVarDeclGlobalStorageFalse) { 935 std::string Main = "main.cpp"; 936 WriteFile(Main, "void foo() { int a; }"); 937 ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, nullptr, 938 0, TUFlags); 939 940 CXCursor C = clang_getTranslationUnitCursor(ClangTU); 941 clang_visitChildren( 942 C, 943 [](CXCursor cursor, CXCursor parent, 944 CXClientData client_data) -> CXChildVisitResult { 945 if (clang_getCursorKind(cursor) == CXCursor_VarDecl) { 946 EXPECT_FALSE(clang_Cursor_hasVarDeclGlobalStorage(cursor)); 947 return CXChildVisit_Break; 948 } 949 return CXChildVisit_Continue; 950 }, 951 nullptr); 952 } 953 954 TEST_F(LibclangParseTest, clang_Cursor_hasVarDeclGlobalStorageTrue) { 955 std::string Main = "main.cpp"; 956 WriteFile(Main, "int a;"); 957 ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, nullptr, 958 0, TUFlags); 959 960 CXCursor C = clang_getTranslationUnitCursor(ClangTU); 961 clang_visitChildren( 962 C, 963 [](CXCursor cursor, CXCursor parent, 964 CXClientData client_data) -> CXChildVisitResult { 965 if (clang_getCursorKind(cursor) == CXCursor_VarDecl) { 966 EXPECT_TRUE(clang_Cursor_hasVarDeclGlobalStorage(cursor)); 967 return CXChildVisit_Break; 968 } 969 return CXChildVisit_Continue; 970 }, 971 nullptr); 972 } 973 974 TEST_F(LibclangParseTest, clang_Cursor_hasVarDeclExternalStorageFalse) { 975 std::string Main = "main.cpp"; 976 WriteFile(Main, "int a;"); 977 ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, nullptr, 978 0, TUFlags); 979 980 CXCursor C = clang_getTranslationUnitCursor(ClangTU); 981 clang_visitChildren( 982 C, 983 [](CXCursor cursor, CXCursor parent, 984 CXClientData client_data) -> CXChildVisitResult { 985 if (clang_getCursorKind(cursor) == CXCursor_VarDecl) { 986 EXPECT_FALSE(clang_Cursor_hasVarDeclExternalStorage(cursor)); 987 return CXChildVisit_Break; 988 } 989 return CXChildVisit_Continue; 990 }, 991 nullptr); 992 } 993 994 TEST_F(LibclangParseTest, clang_Cursor_hasVarDeclExternalStorageTrue) { 995 std::string Main = "main.cpp"; 996 WriteFile(Main, "extern int a;"); 997 ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, nullptr, 998 0, TUFlags); 999 1000 CXCursor C = clang_getTranslationUnitCursor(ClangTU); 1001 clang_visitChildren( 1002 C, 1003 [](CXCursor cursor, CXCursor parent, 1004 CXClientData client_data) -> CXChildVisitResult { 1005 if (clang_getCursorKind(cursor) == CXCursor_VarDecl) { 1006 EXPECT_TRUE(clang_Cursor_hasVarDeclExternalStorage(cursor)); 1007 return CXChildVisit_Break; 1008 } 1009 return CXChildVisit_Continue; 1010 }, 1011 nullptr); 1012 } 1013 1014 TEST_F(LibclangParseTest, clang_getUnqualifiedTypeRemovesQualifiers) { 1015 std::string Header = "header.h"; 1016 WriteFile(Header, "void foo1(const int);\n" 1017 "void foo2(volatile int);\n" 1018 "void foo3(const volatile int);\n" 1019 "void foo4(int* const);\n" 1020 "void foo5(int* volatile);\n" 1021 "void foo6(int* restrict);\n" 1022 "void foo7(int* const volatile);\n" 1023 "void foo8(int* volatile restrict);\n" 1024 "void foo9(int* const restrict);\n" 1025 "void foo10(int* const volatile restrict);\n"); 1026 1027 auto is_qualified = [](CXType type) -> bool { 1028 return clang_isConstQualifiedType(type) || 1029 clang_isVolatileQualifiedType(type) || 1030 clang_isRestrictQualifiedType(type); 1031 }; 1032 1033 ClangTU = clang_parseTranslationUnit(Index, Header.c_str(), nullptr, 0, 1034 nullptr, 0, TUFlags); 1035 1036 Traverse([&is_qualified](CXCursor cursor, CXCursor) { 1037 if (clang_getCursorKind(cursor) == CXCursor_FunctionDecl) { 1038 CXType arg_type = clang_getArgType(clang_getCursorType(cursor), 0); 1039 EXPECT_TRUE(is_qualified(arg_type)) 1040 << "Input data '" << fromCXString(clang_getCursorSpelling(cursor)) 1041 << "' first argument does not have a qualified type."; 1042 1043 CXType unqualified_arg_type = clang_getUnqualifiedType(arg_type); 1044 EXPECT_FALSE(is_qualified(unqualified_arg_type)) 1045 << "The type '" << fromCXString(clang_getTypeSpelling(arg_type)) 1046 << "' was not unqualified after a call to clang_getUnqualifiedType."; 1047 } 1048 1049 return CXChildVisit_Continue; 1050 }); 1051 } 1052 1053 TEST_F(LibclangParseTest, clang_getNonReferenceTypeRemovesRefQualifiers) { 1054 std::string Header = "header.h"; 1055 WriteFile(Header, "void foo1(int&);\n" 1056 "void foo2(int&&);\n"); 1057 1058 auto is_ref_qualified = [](CXType type) -> bool { 1059 return (type.kind == CXType_LValueReference) || 1060 (type.kind == CXType_RValueReference); 1061 }; 1062 1063 const char *Args[] = {"-xc++"}; 1064 ClangTU = clang_parseTranslationUnit(Index, Header.c_str(), Args, 1, nullptr, 1065 0, TUFlags); 1066 1067 Traverse([&is_ref_qualified](CXCursor cursor, CXCursor) { 1068 if (clang_getCursorKind(cursor) == CXCursor_FunctionDecl) { 1069 CXType arg_type = clang_getArgType(clang_getCursorType(cursor), 0); 1070 EXPECT_TRUE(is_ref_qualified(arg_type)) 1071 << "Input data '" << fromCXString(clang_getCursorSpelling(cursor)) 1072 << "' first argument does not have a ref-qualified type."; 1073 1074 CXType non_reference_arg_type = clang_getNonReferenceType(arg_type); 1075 EXPECT_FALSE(is_ref_qualified(non_reference_arg_type)) 1076 << "The type '" << fromCXString(clang_getTypeSpelling(arg_type)) 1077 << "' ref-qualifier was not removed after a call to " 1078 "clang_getNonReferenceType."; 1079 } 1080 1081 return CXChildVisit_Continue; 1082 }); 1083 } 1084 1085 TEST_F(LibclangParseTest, VisitUsingTypeLoc) { 1086 const char testSource[] = R"cpp( 1087 namespace ns1 { 1088 class Class1 1089 { 1090 void fun(); 1091 }; 1092 } 1093 1094 using ns1::Class1; 1095 1096 void Class1::fun() {} 1097 )cpp"; 1098 std::string fileName = "main.cpp"; 1099 WriteFile(fileName, testSource); 1100 const char *Args[] = {"-xc++"}; 1101 ClangTU = clang_parseTranslationUnit(Index, fileName.c_str(), Args, 1, 1102 nullptr, 0, TUFlags); 1103 1104 std::optional<CXCursor> typeRefCsr; 1105 Traverse([&](CXCursor cursor, CXCursor parent) -> CXChildVisitResult { 1106 if (cursor.kind == CXCursor_TypeRef) { 1107 typeRefCsr.emplace(cursor); 1108 } 1109 return CXChildVisit_Recurse; 1110 }); 1111 ASSERT_TRUE(typeRefCsr.has_value()); 1112 EXPECT_EQ(fromCXString(clang_getCursorSpelling(*typeRefCsr)), 1113 "class ns1::Class1"); 1114 } 1115 1116 class LibclangRewriteTest : public LibclangParseTest { 1117 public: 1118 CXRewriter Rew = nullptr; 1119 std::string Filename; 1120 CXFile File = nullptr; 1121 1122 void SetUp() override { 1123 LibclangParseTest::SetUp(); 1124 Filename = "file.cpp"; 1125 WriteFile(Filename, "int main() { return 0; }"); 1126 ClangTU = clang_parseTranslationUnit(Index, Filename.c_str(), nullptr, 0, 1127 nullptr, 0, TUFlags); 1128 Rew = clang_CXRewriter_create(ClangTU); 1129 File = clang_getFile(ClangTU, Filename.c_str()); 1130 } 1131 void TearDown() override { 1132 clang_CXRewriter_dispose(Rew); 1133 LibclangParseTest::TearDown(); 1134 } 1135 }; 1136 1137 static std::string getFileContent(const std::string& Filename) { 1138 std::ifstream RewrittenFile(Filename); 1139 std::string RewrittenFileContent; 1140 std::string Line; 1141 while (std::getline(RewrittenFile, Line)) { 1142 if (RewrittenFileContent.empty()) 1143 RewrittenFileContent = Line; 1144 else { 1145 RewrittenFileContent += "\n" + Line; 1146 } 1147 } 1148 return RewrittenFileContent; 1149 } 1150 1151 TEST_F(LibclangRewriteTest, RewriteReplace) { 1152 CXSourceLocation B = clang_getLocation(ClangTU, File, 1, 5); 1153 CXSourceLocation E = clang_getLocation(ClangTU, File, 1, 9); 1154 CXSourceRange Rng = clang_getRange(B, E); 1155 1156 clang_CXRewriter_replaceText(Rew, Rng, "MAIN"); 1157 1158 ASSERT_EQ(clang_CXRewriter_overwriteChangedFiles(Rew), 0); 1159 EXPECT_EQ(getFileContent(Filename), "int MAIN() { return 0; }"); 1160 } 1161 1162 TEST_F(LibclangRewriteTest, RewriteReplaceShorter) { 1163 CXSourceLocation B = clang_getLocation(ClangTU, File, 1, 5); 1164 CXSourceLocation E = clang_getLocation(ClangTU, File, 1, 9); 1165 CXSourceRange Rng = clang_getRange(B, E); 1166 1167 clang_CXRewriter_replaceText(Rew, Rng, "foo"); 1168 1169 ASSERT_EQ(clang_CXRewriter_overwriteChangedFiles(Rew), 0); 1170 EXPECT_EQ(getFileContent(Filename), "int foo() { return 0; }"); 1171 } 1172 1173 TEST_F(LibclangRewriteTest, RewriteReplaceLonger) { 1174 CXSourceLocation B = clang_getLocation(ClangTU, File, 1, 5); 1175 CXSourceLocation E = clang_getLocation(ClangTU, File, 1, 9); 1176 CXSourceRange Rng = clang_getRange(B, E); 1177 1178 clang_CXRewriter_replaceText(Rew, Rng, "patatino"); 1179 1180 ASSERT_EQ(clang_CXRewriter_overwriteChangedFiles(Rew), 0); 1181 EXPECT_EQ(getFileContent(Filename), "int patatino() { return 0; }"); 1182 } 1183 1184 TEST_F(LibclangRewriteTest, RewriteInsert) { 1185 CXSourceLocation Loc = clang_getLocation(ClangTU, File, 1, 5); 1186 1187 clang_CXRewriter_insertTextBefore(Rew, Loc, "ro"); 1188 1189 ASSERT_EQ(clang_CXRewriter_overwriteChangedFiles(Rew), 0); 1190 EXPECT_EQ(getFileContent(Filename), "int romain() { return 0; }"); 1191 } 1192 1193 TEST_F(LibclangRewriteTest, RewriteRemove) { 1194 CXSourceLocation B = clang_getLocation(ClangTU, File, 1, 5); 1195 CXSourceLocation E = clang_getLocation(ClangTU, File, 1, 9); 1196 CXSourceRange Rng = clang_getRange(B, E); 1197 1198 clang_CXRewriter_removeText(Rew, Rng); 1199 1200 ASSERT_EQ(clang_CXRewriter_overwriteChangedFiles(Rew), 0); 1201 EXPECT_EQ(getFileContent(Filename), "int () { return 0; }"); 1202 } 1203