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