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