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 "llvm/ADT/StringRef.h" 11 #include "llvm/Support/Debug.h" 12 #include "llvm/Support/FileSystem.h" 13 #include "llvm/Support/Path.h" 14 #include "llvm/Support/raw_ostream.h" 15 #include "gtest/gtest.h" 16 #include <fstream> 17 #include <functional> 18 #include <map> 19 #include <memory> 20 #include <set> 21 #define DEBUG_TYPE "libclang-test" 22 23 TEST(libclang, clang_parseTranslationUnit2_InvalidArgs) { 24 EXPECT_EQ(CXError_InvalidArguments, 25 clang_parseTranslationUnit2(nullptr, nullptr, nullptr, 0, nullptr, 26 0, 0, nullptr)); 27 } 28 29 TEST(libclang, clang_createTranslationUnit_InvalidArgs) { 30 EXPECT_EQ(nullptr, clang_createTranslationUnit(nullptr, nullptr)); 31 } 32 33 TEST(libclang, clang_createTranslationUnit2_InvalidArgs) { 34 EXPECT_EQ(CXError_InvalidArguments, 35 clang_createTranslationUnit2(nullptr, nullptr, nullptr)); 36 37 CXTranslationUnit TU = reinterpret_cast<CXTranslationUnit>(1); 38 EXPECT_EQ(CXError_InvalidArguments, 39 clang_createTranslationUnit2(nullptr, nullptr, &TU)); 40 EXPECT_EQ(nullptr, TU); 41 } 42 43 namespace { 44 struct TestVFO { 45 const char *Contents; 46 CXVirtualFileOverlay VFO; 47 48 TestVFO(const char *Contents) : Contents(Contents) { 49 VFO = clang_VirtualFileOverlay_create(0); 50 } 51 52 void map(const char *VPath, const char *RPath) { 53 CXErrorCode Err = clang_VirtualFileOverlay_addFileMapping(VFO, VPath, RPath); 54 EXPECT_EQ(Err, CXError_Success); 55 } 56 57 void mapError(const char *VPath, const char *RPath, CXErrorCode ExpErr) { 58 CXErrorCode Err = clang_VirtualFileOverlay_addFileMapping(VFO, VPath, RPath); 59 EXPECT_EQ(Err, ExpErr); 60 } 61 62 ~TestVFO() { 63 if (Contents) { 64 char *BufPtr; 65 unsigned BufSize; 66 clang_VirtualFileOverlay_writeToBuffer(VFO, 0, &BufPtr, &BufSize); 67 std::string BufStr(BufPtr, BufSize); 68 EXPECT_STREQ(Contents, BufStr.c_str()); 69 clang_free(BufPtr); 70 } 71 clang_VirtualFileOverlay_dispose(VFO); 72 } 73 }; 74 } 75 76 TEST(libclang, VirtualFileOverlay_Basic) { 77 const char *contents = 78 "{\n" 79 " 'version': 0,\n" 80 " 'roots': [\n" 81 " {\n" 82 " 'type': 'directory',\n" 83 " 'name': \"/path/virtual\",\n" 84 " 'contents': [\n" 85 " {\n" 86 " 'type': 'file',\n" 87 " 'name': \"foo.h\",\n" 88 " 'external-contents': \"/real/foo.h\"\n" 89 " }\n" 90 " ]\n" 91 " }\n" 92 " ]\n" 93 "}\n"; 94 TestVFO T(contents); 95 T.map("/path/virtual/foo.h", "/real/foo.h"); 96 } 97 98 TEST(libclang, VirtualFileOverlay_Unicode) { 99 const char *contents = 100 "{\n" 101 " 'version': 0,\n" 102 " 'roots': [\n" 103 " {\n" 104 " 'type': 'directory',\n" 105 " 'name': \"/path/\\u266B\",\n" 106 " 'contents': [\n" 107 " {\n" 108 " 'type': 'file',\n" 109 " 'name': \"\\u2602.h\",\n" 110 " 'external-contents': \"/real/\\u2602.h\"\n" 111 " }\n" 112 " ]\n" 113 " }\n" 114 " ]\n" 115 "}\n"; 116 TestVFO T(contents); 117 T.map("/path/♫/☂.h", "/real/☂.h"); 118 } 119 120 TEST(libclang, VirtualFileOverlay_InvalidArgs) { 121 TestVFO T(nullptr); 122 T.mapError("/path/./virtual/../foo.h", "/real/foo.h", 123 CXError_InvalidArguments); 124 } 125 126 TEST(libclang, VirtualFileOverlay_RemapDirectories) { 127 const char *contents = 128 "{\n" 129 " 'version': 0,\n" 130 " 'roots': [\n" 131 " {\n" 132 " 'type': 'directory',\n" 133 " 'name': \"/another/dir\",\n" 134 " 'contents': [\n" 135 " {\n" 136 " 'type': 'file',\n" 137 " 'name': \"foo2.h\",\n" 138 " 'external-contents': \"/real/foo2.h\"\n" 139 " }\n" 140 " ]\n" 141 " },\n" 142 " {\n" 143 " 'type': 'directory',\n" 144 " 'name': \"/path/virtual/dir\",\n" 145 " 'contents': [\n" 146 " {\n" 147 " 'type': 'file',\n" 148 " 'name': \"foo1.h\",\n" 149 " 'external-contents': \"/real/foo1.h\"\n" 150 " },\n" 151 " {\n" 152 " 'type': 'file',\n" 153 " 'name': \"foo3.h\",\n" 154 " 'external-contents': \"/real/foo3.h\"\n" 155 " },\n" 156 " {\n" 157 " 'type': 'directory',\n" 158 " 'name': \"in/subdir\",\n" 159 " 'contents': [\n" 160 " {\n" 161 " 'type': 'file',\n" 162 " 'name': \"foo4.h\",\n" 163 " 'external-contents': \"/real/foo4.h\"\n" 164 " }\n" 165 " ]\n" 166 " }\n" 167 " ]\n" 168 " }\n" 169 " ]\n" 170 "}\n"; 171 TestVFO T(contents); 172 T.map("/path/virtual/dir/foo1.h", "/real/foo1.h"); 173 T.map("/another/dir/foo2.h", "/real/foo2.h"); 174 T.map("/path/virtual/dir/foo3.h", "/real/foo3.h"); 175 T.map("/path/virtual/dir/in/subdir/foo4.h", "/real/foo4.h"); 176 } 177 178 TEST(libclang, VirtualFileOverlay_CaseInsensitive) { 179 const char *contents = 180 "{\n" 181 " 'version': 0,\n" 182 " 'case-sensitive': 'false',\n" 183 " 'roots': [\n" 184 " {\n" 185 " 'type': 'directory',\n" 186 " 'name': \"/path/virtual\",\n" 187 " 'contents': [\n" 188 " {\n" 189 " 'type': 'file',\n" 190 " 'name': \"foo.h\",\n" 191 " 'external-contents': \"/real/foo.h\"\n" 192 " }\n" 193 " ]\n" 194 " }\n" 195 " ]\n" 196 "}\n"; 197 TestVFO T(contents); 198 T.map("/path/virtual/foo.h", "/real/foo.h"); 199 clang_VirtualFileOverlay_setCaseSensitivity(T.VFO, false); 200 } 201 202 TEST(libclang, VirtualFileOverlay_SharedPrefix) { 203 const char *contents = 204 "{\n" 205 " 'version': 0,\n" 206 " 'roots': [\n" 207 " {\n" 208 " 'type': 'directory',\n" 209 " 'name': \"/path/foo\",\n" 210 " 'contents': [\n" 211 " {\n" 212 " 'type': 'file',\n" 213 " 'name': \"bar\",\n" 214 " 'external-contents': \"/real/bar\"\n" 215 " },\n" 216 " {\n" 217 " 'type': 'file',\n" 218 " 'name': \"bar.h\",\n" 219 " 'external-contents': \"/real/bar.h\"\n" 220 " }\n" 221 " ]\n" 222 " },\n" 223 " {\n" 224 " 'type': 'directory',\n" 225 " 'name': \"/path/foobar\",\n" 226 " 'contents': [\n" 227 " {\n" 228 " 'type': 'file',\n" 229 " 'name': \"baz.h\",\n" 230 " 'external-contents': \"/real/baz.h\"\n" 231 " }\n" 232 " ]\n" 233 " },\n" 234 " {\n" 235 " 'type': 'directory',\n" 236 " 'name': \"/path\",\n" 237 " 'contents': [\n" 238 " {\n" 239 " 'type': 'file',\n" 240 " 'name': \"foobarbaz.h\",\n" 241 " 'external-contents': \"/real/foobarbaz.h\"\n" 242 " }\n" 243 " ]\n" 244 " }\n" 245 " ]\n" 246 "}\n"; 247 TestVFO T(contents); 248 T.map("/path/foo/bar.h", "/real/bar.h"); 249 T.map("/path/foo/bar", "/real/bar"); 250 T.map("/path/foobar/baz.h", "/real/baz.h"); 251 T.map("/path/foobarbaz.h", "/real/foobarbaz.h"); 252 } 253 254 TEST(libclang, VirtualFileOverlay_AdjacentDirectory) { 255 const char *contents = 256 "{\n" 257 " 'version': 0,\n" 258 " 'roots': [\n" 259 " {\n" 260 " 'type': 'directory',\n" 261 " 'name': \"/path/dir1\",\n" 262 " 'contents': [\n" 263 " {\n" 264 " 'type': 'file',\n" 265 " 'name': \"foo.h\",\n" 266 " 'external-contents': \"/real/foo.h\"\n" 267 " },\n" 268 " {\n" 269 " 'type': 'directory',\n" 270 " 'name': \"subdir\",\n" 271 " 'contents': [\n" 272 " {\n" 273 " 'type': 'file',\n" 274 " 'name': \"bar.h\",\n" 275 " 'external-contents': \"/real/bar.h\"\n" 276 " }\n" 277 " ]\n" 278 " }\n" 279 " ]\n" 280 " },\n" 281 " {\n" 282 " 'type': 'directory',\n" 283 " 'name': \"/path/dir2\",\n" 284 " 'contents': [\n" 285 " {\n" 286 " 'type': 'file',\n" 287 " 'name': \"baz.h\",\n" 288 " 'external-contents': \"/real/baz.h\"\n" 289 " }\n" 290 " ]\n" 291 " }\n" 292 " ]\n" 293 "}\n"; 294 TestVFO T(contents); 295 T.map("/path/dir1/foo.h", "/real/foo.h"); 296 T.map("/path/dir1/subdir/bar.h", "/real/bar.h"); 297 T.map("/path/dir2/baz.h", "/real/baz.h"); 298 } 299 300 TEST(libclang, VirtualFileOverlay_TopLevel) { 301 const char *contents = 302 "{\n" 303 " 'version': 0,\n" 304 " 'roots': [\n" 305 " {\n" 306 " 'type': 'directory',\n" 307 " 'name': \"/\",\n" 308 " 'contents': [\n" 309 " {\n" 310 " 'type': 'file',\n" 311 " 'name': \"foo.h\",\n" 312 " 'external-contents': \"/real/foo.h\"\n" 313 " }\n" 314 " ]\n" 315 " }\n" 316 " ]\n" 317 "}\n"; 318 TestVFO T(contents); 319 T.map("/foo.h", "/real/foo.h"); 320 } 321 322 TEST(libclang, VirtualFileOverlay_Empty) { 323 const char *contents = 324 "{\n" 325 " 'version': 0,\n" 326 " 'roots': [\n" 327 " ]\n" 328 "}\n"; 329 TestVFO T(contents); 330 } 331 332 TEST(libclang, ModuleMapDescriptor) { 333 const char *Contents = 334 "framework module TestFrame {\n" 335 " umbrella header \"TestFrame.h\"\n" 336 "\n" 337 " export *\n" 338 " module * { export * }\n" 339 "}\n"; 340 341 CXModuleMapDescriptor MMD = clang_ModuleMapDescriptor_create(0); 342 343 clang_ModuleMapDescriptor_setFrameworkModuleName(MMD, "TestFrame"); 344 clang_ModuleMapDescriptor_setUmbrellaHeader(MMD, "TestFrame.h"); 345 346 char *BufPtr; 347 unsigned BufSize; 348 clang_ModuleMapDescriptor_writeToBuffer(MMD, 0, &BufPtr, &BufSize); 349 std::string BufStr(BufPtr, BufSize); 350 EXPECT_STREQ(Contents, BufStr.c_str()); 351 clang_free(BufPtr); 352 clang_ModuleMapDescriptor_dispose(MMD); 353 } 354 355 class LibclangParseTest : public ::testing::Test { 356 std::set<std::string> Files; 357 typedef std::unique_ptr<std::string> fixed_addr_string; 358 std::map<fixed_addr_string, fixed_addr_string> UnsavedFileContents; 359 public: 360 std::string TestDir; 361 CXIndex Index; 362 CXTranslationUnit ClangTU; 363 unsigned TUFlags; 364 std::vector<CXUnsavedFile> UnsavedFiles; 365 366 void SetUp() override { 367 llvm::SmallString<256> Dir; 368 ASSERT_FALSE(llvm::sys::fs::createUniqueDirectory("libclang-test", Dir)); 369 TestDir = Dir.str(); 370 TUFlags = CXTranslationUnit_DetailedPreprocessingRecord | 371 clang_defaultEditingTranslationUnitOptions(); 372 Index = clang_createIndex(0, 0); 373 ClangTU = nullptr; 374 } 375 void TearDown() override { 376 clang_disposeTranslationUnit(ClangTU); 377 clang_disposeIndex(Index); 378 for (const std::string &Path : Files) 379 llvm::sys::fs::remove(Path); 380 llvm::sys::fs::remove(TestDir); 381 } 382 void WriteFile(std::string &Filename, const std::string &Contents) { 383 if (!llvm::sys::path::is_absolute(Filename)) { 384 llvm::SmallString<256> Path(TestDir); 385 llvm::sys::path::append(Path, Filename); 386 Filename = Path.str(); 387 Files.insert(Filename); 388 } 389 llvm::sys::fs::create_directories(llvm::sys::path::parent_path(Filename)); 390 std::ofstream OS(Filename); 391 OS << Contents; 392 assert(OS.good()); 393 } 394 void MapUnsavedFile(std::string Filename, const std::string &Contents) { 395 if (!llvm::sys::path::is_absolute(Filename)) { 396 llvm::SmallString<256> Path(TestDir); 397 llvm::sys::path::append(Path, Filename); 398 Filename = Path.str(); 399 } 400 auto it = UnsavedFileContents.insert(std::make_pair( 401 fixed_addr_string(new std::string(Filename)), 402 fixed_addr_string(new std::string(Contents)))); 403 UnsavedFiles.push_back({ 404 it.first->first->c_str(), // filename 405 it.first->second->c_str(), // contents 406 it.first->second->size() // length 407 }); 408 } 409 template<typename F> 410 void Traverse(const F &TraversalFunctor) { 411 CXCursor TuCursor = clang_getTranslationUnitCursor(ClangTU); 412 std::reference_wrapper<const F> FunctorRef = std::cref(TraversalFunctor); 413 clang_visitChildren(TuCursor, 414 &TraverseStateless<std::reference_wrapper<const F>>, 415 &FunctorRef); 416 } 417 private: 418 template<typename TState> 419 static CXChildVisitResult TraverseStateless(CXCursor cx, CXCursor parent, 420 CXClientData data) { 421 TState *State = static_cast<TState*>(data); 422 return State->get()(cx, parent); 423 } 424 }; 425 426 TEST_F(LibclangParseTest, AllSkippedRanges) { 427 std::string Header = "header.h", Main = "main.cpp"; 428 WriteFile(Header, 429 "#ifdef MANGOS\n" 430 "printf(\"mmm\");\n" 431 "#endif"); 432 WriteFile(Main, 433 "#include \"header.h\"\n" 434 "#ifdef KIWIS\n" 435 "printf(\"mmm!!\");\n" 436 "#endif"); 437 438 ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, 439 nullptr, 0, TUFlags); 440 441 CXSourceRangeList *Ranges = clang_getAllSkippedRanges(ClangTU); 442 EXPECT_EQ(2U, Ranges->count); 443 444 CXSourceLocation cxl; 445 unsigned line; 446 cxl = clang_getRangeStart(Ranges->ranges[0]); 447 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 448 EXPECT_EQ(1U, line); 449 cxl = clang_getRangeEnd(Ranges->ranges[0]); 450 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 451 EXPECT_EQ(3U, line); 452 453 cxl = clang_getRangeStart(Ranges->ranges[1]); 454 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 455 EXPECT_EQ(2U, line); 456 cxl = clang_getRangeEnd(Ranges->ranges[1]); 457 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 458 EXPECT_EQ(4U, line); 459 460 clang_disposeSourceRangeList(Ranges); 461 } 462 463 TEST_F(LibclangParseTest, EvaluateChildExpression) { 464 std::string Main = "main.m"; 465 WriteFile(Main, "#define kFOO @\"foo\"\n" 466 "void foobar(void) {\n" 467 " {kFOO;}\n" 468 "}\n"); 469 ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, nullptr, 470 0, TUFlags); 471 472 CXCursor C = clang_getTranslationUnitCursor(ClangTU); 473 clang_visitChildren( 474 C, 475 [](CXCursor cursor, CXCursor parent, 476 CXClientData client_data) -> CXChildVisitResult { 477 if (clang_getCursorKind(cursor) == CXCursor_FunctionDecl) { 478 int numberedStmt = 0; 479 clang_visitChildren( 480 cursor, 481 [](CXCursor cursor, CXCursor parent, 482 CXClientData client_data) -> CXChildVisitResult { 483 int &numberedStmt = *((int *)client_data); 484 if (clang_getCursorKind(cursor) == CXCursor_CompoundStmt) { 485 if (numberedStmt) { 486 CXEvalResult RE = clang_Cursor_Evaluate(cursor); 487 EXPECT_NE(RE, nullptr); 488 EXPECT_EQ(clang_EvalResult_getKind(RE), 489 CXEval_ObjCStrLiteral); 490 clang_EvalResult_dispose(RE); 491 return CXChildVisit_Break; 492 } 493 numberedStmt++; 494 } 495 return CXChildVisit_Recurse; 496 }, 497 &numberedStmt); 498 EXPECT_EQ(numberedStmt, 1); 499 } 500 return CXChildVisit_Continue; 501 }, 502 nullptr); 503 } 504 505 class LibclangReparseTest : public LibclangParseTest { 506 public: 507 void DisplayDiagnostics() { 508 unsigned NumDiagnostics = clang_getNumDiagnostics(ClangTU); 509 for (unsigned i = 0; i < NumDiagnostics; ++i) { 510 auto Diag = clang_getDiagnostic(ClangTU, i); 511 LLVM_DEBUG(llvm::dbgs() 512 << clang_getCString(clang_formatDiagnostic( 513 Diag, clang_defaultDiagnosticDisplayOptions())) 514 << "\n"); 515 clang_disposeDiagnostic(Diag); 516 } 517 } 518 bool ReparseTU(unsigned num_unsaved_files, CXUnsavedFile* unsaved_files) { 519 if (clang_reparseTranslationUnit(ClangTU, num_unsaved_files, unsaved_files, 520 clang_defaultReparseOptions(ClangTU))) { 521 LLVM_DEBUG(llvm::dbgs() << "Reparse failed\n"); 522 return false; 523 } 524 DisplayDiagnostics(); 525 return true; 526 } 527 }; 528 529 TEST_F(LibclangReparseTest, FileName) { 530 std::string CppName = "main.cpp"; 531 WriteFile(CppName, "int main() {}"); 532 ClangTU = clang_parseTranslationUnit(Index, CppName.c_str(), nullptr, 0, 533 nullptr, 0, TUFlags); 534 CXFile cxf = clang_getFile(ClangTU, CppName.c_str()); 535 536 CXString cxname = clang_getFileName(cxf); 537 ASSERT_STREQ(clang_getCString(cxname), CppName.c_str()); 538 clang_disposeString(cxname); 539 540 cxname = clang_File_tryGetRealPathName(cxf); 541 ASSERT_TRUE(llvm::StringRef(clang_getCString(cxname)).endswith("main.cpp")); 542 clang_disposeString(cxname); 543 } 544 545 TEST_F(LibclangReparseTest, Reparse) { 546 const char *HeaderTop = "#ifndef H\n#define H\nstruct Foo { int bar;"; 547 const char *HeaderBottom = "\n};\n#endif\n"; 548 const char *CppFile = "#include \"HeaderFile.h\"\nint main() {" 549 " Foo foo; foo.bar = 7; foo.baz = 8; }\n"; 550 std::string HeaderName = "HeaderFile.h"; 551 std::string CppName = "CppFile.cpp"; 552 WriteFile(CppName, CppFile); 553 WriteFile(HeaderName, std::string(HeaderTop) + HeaderBottom); 554 555 ClangTU = clang_parseTranslationUnit(Index, CppName.c_str(), nullptr, 0, 556 nullptr, 0, TUFlags); 557 EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU)); 558 DisplayDiagnostics(); 559 560 // Immedaitely reparse. 561 ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */)); 562 EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU)); 563 564 std::string NewHeaderContents = 565 std::string(HeaderTop) + "int baz;" + HeaderBottom; 566 WriteFile(HeaderName, NewHeaderContents); 567 568 // Reparse after fix. 569 ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */)); 570 EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU)); 571 } 572 573 TEST_F(LibclangReparseTest, ReparseWithModule) { 574 const char *HeaderTop = "#ifndef H\n#define H\nstruct Foo { int bar;"; 575 const char *HeaderBottom = "\n};\n#endif\n"; 576 const char *MFile = "#include \"HeaderFile.h\"\nint main() {" 577 " struct Foo foo; foo.bar = 7; foo.baz = 8; }\n"; 578 const char *ModFile = "module A { header \"HeaderFile.h\" }\n"; 579 std::string HeaderName = "HeaderFile.h"; 580 std::string MName = "MFile.m"; 581 std::string ModName = "module.modulemap"; 582 WriteFile(MName, MFile); 583 WriteFile(HeaderName, std::string(HeaderTop) + HeaderBottom); 584 WriteFile(ModName, ModFile); 585 586 std::string ModulesCache = std::string("-fmodules-cache-path=") + TestDir; 587 const char *Args[] = { "-fmodules", ModulesCache.c_str(), 588 "-I", TestDir.c_str() }; 589 int NumArgs = sizeof(Args) / sizeof(Args[0]); 590 ClangTU = clang_parseTranslationUnit(Index, MName.c_str(), Args, NumArgs, 591 nullptr, 0, TUFlags); 592 EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU)); 593 DisplayDiagnostics(); 594 595 // Immedaitely reparse. 596 ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */)); 597 EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU)); 598 599 std::string NewHeaderContents = 600 std::string(HeaderTop) + "int baz;" + HeaderBottom; 601 WriteFile(HeaderName, NewHeaderContents); 602 603 // Reparse after fix. 604 ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */)); 605 EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU)); 606 } 607 608 TEST_F(LibclangReparseTest, clang_parseTranslationUnit2FullArgv) { 609 // Provide a fake GCC 99.9.9 standard library that always overrides any local 610 // GCC installation. 611 std::string EmptyFiles[] = {"lib/gcc/arm-linux-gnueabi/99.9.9/crtbegin.o", 612 "include/arm-linux-gnueabi/.keep", 613 "include/c++/99.9.9/vector"}; 614 615 for (auto &Name : EmptyFiles) 616 WriteFile(Name, "\n"); 617 618 std::string Filename = "test.cc"; 619 WriteFile(Filename, "#include <vector>\n"); 620 621 std::string Clang = "bin/clang"; 622 WriteFile(Clang, ""); 623 624 const char *Argv[] = {Clang.c_str(), "-target", "arm-linux-gnueabi", 625 "-stdlib=libstdc++", "--gcc-toolchain="}; 626 627 EXPECT_EQ(CXError_Success, 628 clang_parseTranslationUnit2FullArgv(Index, Filename.c_str(), Argv, 629 sizeof(Argv) / sizeof(Argv[0]), 630 nullptr, 0, TUFlags, &ClangTU)); 631 EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU)); 632 DisplayDiagnostics(); 633 } 634 635 class LibclangPrintingPolicyTest : public LibclangParseTest { 636 public: 637 CXPrintingPolicy Policy = nullptr; 638 639 void SetUp() override { 640 LibclangParseTest::SetUp(); 641 std::string File = "file.cpp"; 642 WriteFile(File, "int i;\n"); 643 ClangTU = clang_parseTranslationUnit(Index, File.c_str(), nullptr, 0, 644 nullptr, 0, TUFlags); 645 CXCursor TUCursor = clang_getTranslationUnitCursor(ClangTU); 646 Policy = clang_getCursorPrintingPolicy(TUCursor); 647 } 648 void TearDown() override { 649 clang_PrintingPolicy_dispose(Policy); 650 LibclangParseTest::TearDown(); 651 } 652 }; 653 654 TEST_F(LibclangPrintingPolicyTest, SetAndGetProperties) { 655 for (unsigned Value = 0; Value < 2; ++Value) { 656 for (int I = 0; I < CXPrintingPolicy_LastProperty; ++I) { 657 auto Property = static_cast<enum CXPrintingPolicyProperty>(I); 658 659 clang_PrintingPolicy_setProperty(Policy, Property, Value); 660 EXPECT_EQ(Value, clang_PrintingPolicy_getProperty(Policy, Property)); 661 } 662 } 663 } 664 665 TEST_F(LibclangReparseTest, PreprocessorSkippedRanges) { 666 std::string Header = "header.h", Main = "main.cpp"; 667 WriteFile(Header, 668 "#ifdef MANGOS\n" 669 "printf(\"mmm\");\n" 670 "#endif"); 671 WriteFile(Main, 672 "#include \"header.h\"\n" 673 "#ifdef GUAVA\n" 674 "#endif\n" 675 "#ifdef KIWIS\n" 676 "printf(\"mmm!!\");\n" 677 "#endif"); 678 679 for (int i = 0; i != 3; ++i) { 680 unsigned flags = TUFlags | CXTranslationUnit_PrecompiledPreamble; 681 if (i == 2) 682 flags |= CXTranslationUnit_CreatePreambleOnFirstParse; 683 684 if (i != 0) 685 clang_disposeTranslationUnit(ClangTU); // dispose from previous iter 686 687 // parse once 688 ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, 689 nullptr, 0, flags); 690 if (i != 0) { 691 // reparse 692 ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */)); 693 } 694 695 // Check all ranges are there 696 CXSourceRangeList *Ranges = clang_getAllSkippedRanges(ClangTU); 697 EXPECT_EQ(3U, Ranges->count); 698 699 CXSourceLocation cxl; 700 unsigned line; 701 cxl = clang_getRangeStart(Ranges->ranges[0]); 702 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 703 EXPECT_EQ(1U, line); 704 cxl = clang_getRangeEnd(Ranges->ranges[0]); 705 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 706 EXPECT_EQ(3U, line); 707 708 cxl = clang_getRangeStart(Ranges->ranges[1]); 709 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 710 EXPECT_EQ(2U, line); 711 cxl = clang_getRangeEnd(Ranges->ranges[1]); 712 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 713 EXPECT_EQ(3U, line); 714 715 cxl = clang_getRangeStart(Ranges->ranges[2]); 716 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 717 EXPECT_EQ(4U, line); 718 cxl = clang_getRangeEnd(Ranges->ranges[2]); 719 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 720 EXPECT_EQ(6U, line); 721 722 clang_disposeSourceRangeList(Ranges); 723 724 // Check obtaining ranges by each file works 725 CXFile cxf = clang_getFile(ClangTU, Header.c_str()); 726 Ranges = clang_getSkippedRanges(ClangTU, cxf); 727 EXPECT_EQ(1U, Ranges->count); 728 cxl = clang_getRangeStart(Ranges->ranges[0]); 729 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 730 EXPECT_EQ(1U, line); 731 clang_disposeSourceRangeList(Ranges); 732 733 cxf = clang_getFile(ClangTU, Main.c_str()); 734 Ranges = clang_getSkippedRanges(ClangTU, cxf); 735 EXPECT_EQ(2U, Ranges->count); 736 cxl = clang_getRangeStart(Ranges->ranges[0]); 737 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 738 EXPECT_EQ(2U, line); 739 cxl = clang_getRangeStart(Ranges->ranges[1]); 740 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr); 741 EXPECT_EQ(4U, line); 742 clang_disposeSourceRangeList(Ranges); 743 } 744 } 745 746 class LibclangSerializationTest : public LibclangParseTest { 747 public: 748 bool SaveAndLoadTU(const std::string &Filename) { 749 unsigned options = clang_defaultSaveOptions(ClangTU); 750 if (clang_saveTranslationUnit(ClangTU, Filename.c_str(), options) != 751 CXSaveError_None) { 752 LLVM_DEBUG(llvm::dbgs() << "Saving failed\n"); 753 return false; 754 } 755 756 clang_disposeTranslationUnit(ClangTU); 757 758 ClangTU = clang_createTranslationUnit(Index, Filename.c_str()); 759 760 if (!ClangTU) { 761 LLVM_DEBUG(llvm::dbgs() << "Loading failed\n"); 762 return false; 763 } 764 765 return true; 766 } 767 }; 768 769 TEST_F(LibclangSerializationTest, TokenKindsAreCorrectAfterLoading) { 770 // Ensure that "class" is recognized as a keyword token after serializing 771 // and reloading the AST, as it is not a keyword for the default LangOptions. 772 std::string HeaderName = "test.h"; 773 WriteFile(HeaderName, "enum class Something {};"); 774 775 const char *Argv[] = {"-xc++-header", "-std=c++11"}; 776 777 ClangTU = clang_parseTranslationUnit(Index, HeaderName.c_str(), Argv, 778 sizeof(Argv) / sizeof(Argv[0]), nullptr, 779 0, TUFlags); 780 781 auto CheckTokenKinds = [=]() { 782 CXSourceRange Range = 783 clang_getCursorExtent(clang_getTranslationUnitCursor(ClangTU)); 784 785 CXToken *Tokens; 786 unsigned int NumTokens; 787 clang_tokenize(ClangTU, Range, &Tokens, &NumTokens); 788 789 ASSERT_EQ(6u, NumTokens); 790 EXPECT_EQ(CXToken_Keyword, clang_getTokenKind(Tokens[0])); 791 EXPECT_EQ(CXToken_Keyword, clang_getTokenKind(Tokens[1])); 792 EXPECT_EQ(CXToken_Identifier, clang_getTokenKind(Tokens[2])); 793 EXPECT_EQ(CXToken_Punctuation, clang_getTokenKind(Tokens[3])); 794 EXPECT_EQ(CXToken_Punctuation, clang_getTokenKind(Tokens[4])); 795 EXPECT_EQ(CXToken_Punctuation, clang_getTokenKind(Tokens[5])); 796 797 clang_disposeTokens(ClangTU, Tokens, NumTokens); 798 }; 799 800 CheckTokenKinds(); 801 802 std::string ASTName = "test.ast"; 803 WriteFile(ASTName, ""); 804 805 ASSERT_TRUE(SaveAndLoadTU(ASTName)); 806 807 CheckTokenKinds(); 808 } 809