1462 lines · cpp
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-exception6//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 27TEST(libclang, clang_parseTranslationUnit2_InvalidArgs) {28 EXPECT_EQ(CXError_InvalidArguments,29 clang_parseTranslationUnit2(nullptr, nullptr, nullptr, 0, nullptr,30 0, 0, nullptr));31}32 33TEST(libclang, clang_createTranslationUnit_InvalidArgs) {34 EXPECT_EQ(nullptr, clang_createTranslationUnit(nullptr, nullptr));35}36 37TEST(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 47namespace {48struct 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 80TEST(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 102TEST(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 124TEST(libclang, VirtualFileOverlay_InvalidArgs) {125 TestVFO T(nullptr);126 T.mapError("/path/./virtual/../foo.h", "/real/foo.h",127 CXError_InvalidArguments);128}129 130TEST(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 182TEST(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 206TEST(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 258TEST(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 304TEST(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 326TEST(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 336TEST(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 359TEST_F(LibclangParseTest, GlobalOptions) {360 EXPECT_EQ(clang_CXIndex_getGlobalOptions(Index), CXGlobalOpt_None);361}362 363class LibclangIndexOptionsTest : public LibclangParseTest {364 virtual void AdjustOptions(CXIndexOptions &Opts) {}365 366protected: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 377TEST_F(LibclangIndexOptionsTest, GlobalOptions) {378 EXPECT_EQ(clang_CXIndex_getGlobalOptions(Index), CXGlobalOpt_None);379}380 381class LibclangIndexingEnabledIndexOptionsTest382 : public LibclangIndexOptionsTest {383 void AdjustOptions(CXIndexOptions &Opts) override {384 Opts.ThreadBackgroundPriorityForIndexing = CXChoice_Enabled;385 }386};387 388TEST_F(LibclangIndexingEnabledIndexOptionsTest, GlobalOptions) {389 EXPECT_EQ(clang_CXIndex_getGlobalOptions(Index),390 CXGlobalOpt_ThreadBackgroundPriorityForIndexing);391}392 393class LibclangIndexingDisabledEditingEnabledIndexOptionsTest394 : public LibclangIndexOptionsTest {395 void AdjustOptions(CXIndexOptions &Opts) override {396 Opts.ThreadBackgroundPriorityForIndexing = CXChoice_Disabled;397 Opts.ThreadBackgroundPriorityForEditing = CXChoice_Enabled;398 }399};400 401TEST_F(LibclangIndexingDisabledEditingEnabledIndexOptionsTest, GlobalOptions) {402 EXPECT_EQ(clang_CXIndex_getGlobalOptions(Index),403 CXGlobalOpt_ThreadBackgroundPriorityForEditing);404}405 406class LibclangBothEnabledIndexOptionsTest : public LibclangIndexOptionsTest {407 void AdjustOptions(CXIndexOptions &Opts) override {408 Opts.ThreadBackgroundPriorityForIndexing = CXChoice_Enabled;409 Opts.ThreadBackgroundPriorityForEditing = CXChoice_Enabled;410 }411};412 413TEST_F(LibclangBothEnabledIndexOptionsTest, GlobalOptions) {414 EXPECT_EQ(clang_CXIndex_getGlobalOptions(Index),415 CXGlobalOpt_ThreadBackgroundPriorityForAll);416}417 418class LibclangPreambleStorageTest : public LibclangParseTest {419 std::string Main = "main.cpp";420 421protected: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 433public: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.starts_with("preamble-"));455 EXPECT_TRUE(Filename.ends_with(".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 is461 // created with default permissions and replaces the .pch file along462 // with its permissions. Therefore the permissions set in463 // 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 472class LibclangNotOverriddenPreambleStoragePathTest473 : public LibclangPreambleStorageTest {474protected:475 void CreateIndex() override {476 InitializePreambleDir();477 LibclangPreambleStorageTest::CreateIndex();478 }479};480 481class LibclangSetPreambleStoragePathTest : public LibclangPreambleStorageTest {482 virtual bool StorePreamblesInMemory() { return false; }483 virtual const char *PreambleStoragePath() = 0;484 485protected:486 void CreateIndex() override {487 InitializePreambleDir();488 489 CXIndexOptions Opts{};490 Opts.Size = sizeof(CXIndexOptions);491 Opts.StorePreamblesInMemory = StorePreamblesInMemory();492 Opts.PreambleStoragePath = PreambleStoragePath();493 Index = clang_createIndexWithOptions(&Opts);494 ASSERT_TRUE(Index);495 }496};497 498class LibclangNullPreambleStoragePathTest499 : public LibclangSetPreambleStoragePathTest {500 const char *PreambleStoragePath() override { return nullptr; }501};502class LibclangEmptyPreambleStoragePathTest503 : public LibclangSetPreambleStoragePathTest {504 const char *PreambleStoragePath() override { return ""; }505};506class LibclangPreambleDirPreambleStoragePathTest507 : public LibclangSetPreambleStoragePathTest {508 const char *PreambleStoragePath() override { return PreambleDir.c_str(); }509};510 511class LibclangStoreInMemoryNullPreambleStoragePathTest512 : public LibclangNullPreambleStoragePathTest {513 bool StorePreamblesInMemory() override { return true; }514};515class LibclangStoreInMemoryEmptyPreambleStoragePathTest516 : public LibclangEmptyPreambleStoragePathTest {517 bool StorePreamblesInMemory() override { return true; }518};519class LibclangStoreInMemoryPreambleDirPreambleStoragePathTest520 : public LibclangPreambleDirPreambleStoragePathTest {521 bool StorePreamblesInMemory() override { return true; }522};523 524TEST_F(LibclangNotOverriddenPreambleStoragePathTest, CountPreambles) {525 CountPreamblesInPreambleDir(0);526}527TEST_F(LibclangNullPreambleStoragePathTest, CountPreambles) {528 CountPreamblesInPreambleDir(0);529}530TEST_F(LibclangEmptyPreambleStoragePathTest, CountPreambles) {531 CountPreamblesInPreambleDir(0);532}533TEST_F(LibclangPreambleDirPreambleStoragePathTest, CountPreambles) {534 CountPreamblesInPreambleDir(1);535}536TEST_F(LibclangStoreInMemoryNullPreambleStoragePathTest, CountPreambles) {537 CountPreamblesInPreambleDir(0);538}539TEST_F(LibclangStoreInMemoryEmptyPreambleStoragePathTest, CountPreambles) {540 CountPreamblesInPreambleDir(0);541}542TEST_F(LibclangStoreInMemoryPreambleDirPreambleStoragePathTest,543 CountPreambles) {544 CountPreamblesInPreambleDir(0);545}546 547TEST_F(LibclangParseTest, AllSkippedRanges) {548 std::string Header = "header.h", Main = "main.cpp";549 WriteFile(Header,550 "#ifdef MANGOS\n"551 "printf(\"mmm\");\n"552 "#endif");553 WriteFile(Main,554 "#include \"header.h\"\n"555 "#ifdef KIWIS\n"556 "printf(\"mmm!!\");\n"557 "#endif");558 559 ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0,560 nullptr, 0, TUFlags);561 562 CXSourceRangeList *Ranges = clang_getAllSkippedRanges(ClangTU);563 EXPECT_EQ(2U, Ranges->count);564 565 CXSourceLocation cxl;566 unsigned line;567 cxl = clang_getRangeStart(Ranges->ranges[0]);568 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);569 EXPECT_EQ(1U, line);570 cxl = clang_getRangeEnd(Ranges->ranges[0]);571 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);572 EXPECT_EQ(3U, line);573 574 cxl = clang_getRangeStart(Ranges->ranges[1]);575 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);576 EXPECT_EQ(2U, line);577 cxl = clang_getRangeEnd(Ranges->ranges[1]);578 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);579 EXPECT_EQ(4U, line);580 581 clang_disposeSourceRangeList(Ranges);582}583 584TEST_F(LibclangParseTest, EvaluateChildExpression) {585 std::string Main = "main.m";586 WriteFile(Main, "#define kFOO @\"foo\"\n"587 "void foobar(void) {\n"588 " {kFOO;}\n"589 "}\n");590 ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, nullptr,591 0, TUFlags);592 593 CXCursor C = clang_getTranslationUnitCursor(ClangTU);594 clang_visitChildren(595 C,596 [](CXCursor cursor, CXCursor parent,597 CXClientData client_data) -> CXChildVisitResult {598 if (clang_getCursorKind(cursor) == CXCursor_FunctionDecl) {599 int numberedStmt = 0;600 clang_visitChildren(601 cursor,602 [](CXCursor cursor, CXCursor parent,603 CXClientData client_data) -> CXChildVisitResult {604 int &numberedStmt = *((int *)client_data);605 if (clang_getCursorKind(cursor) == CXCursor_CompoundStmt) {606 if (numberedStmt) {607 CXEvalResult RE = clang_Cursor_Evaluate(cursor);608 EXPECT_NE(RE, nullptr);609 EXPECT_EQ(clang_EvalResult_getKind(RE),610 CXEval_ObjCStrLiteral);611 clang_EvalResult_dispose(RE);612 return CXChildVisit_Break;613 }614 numberedStmt++;615 }616 return CXChildVisit_Recurse;617 },618 &numberedStmt);619 EXPECT_EQ(numberedStmt, 1);620 }621 return CXChildVisit_Continue;622 },623 nullptr);624}625 626class LibclangReparseTest : public LibclangParseTest {627public:628 void DisplayDiagnostics() {629 unsigned NumDiagnostics = clang_getNumDiagnostics(ClangTU);630 for (unsigned i = 0; i < NumDiagnostics; ++i) {631 auto Diag = clang_getDiagnostic(ClangTU, i);632 LLVM_DEBUG(llvm::dbgs()633 << clang_getCString(clang_formatDiagnostic(634 Diag, clang_defaultDiagnosticDisplayOptions()))635 << "\n");636 clang_disposeDiagnostic(Diag);637 }638 }639 bool ReparseTU(unsigned num_unsaved_files, CXUnsavedFile* unsaved_files) {640 if (clang_reparseTranslationUnit(ClangTU, num_unsaved_files, unsaved_files,641 clang_defaultReparseOptions(ClangTU))) {642 LLVM_DEBUG(llvm::dbgs() << "Reparse failed\n");643 return false;644 }645 DisplayDiagnostics();646 return true;647 }648};649 650TEST_F(LibclangReparseTest, FileName) {651 std::string CppName = "main.cpp";652 WriteFile(CppName, "int main() {}");653 ClangTU = clang_parseTranslationUnit(Index, CppName.c_str(), nullptr, 0,654 nullptr, 0, TUFlags);655 CXFile cxf = clang_getFile(ClangTU, CppName.c_str());656 657 CXString cxname = clang_getFileName(cxf);658 ASSERT_STREQ(clang_getCString(cxname), CppName.c_str());659 clang_disposeString(cxname);660 661 cxname = clang_File_tryGetRealPathName(cxf);662 ASSERT_TRUE(llvm::StringRef(clang_getCString(cxname)).ends_with("main.cpp"));663 clang_disposeString(cxname);664}665 666TEST_F(LibclangReparseTest, Reparse) {667 const char *HeaderTop = "#ifndef H\n#define H\nstruct Foo { int bar;";668 const char *HeaderBottom = "\n};\n#endif\n";669 const char *CppFile = "#include \"HeaderFile.h\"\nint main() {"670 " Foo foo; foo.bar = 7; foo.baz = 8; }\n";671 std::string HeaderName = "HeaderFile.h";672 std::string CppName = "CppFile.cpp";673 WriteFile(CppName, CppFile);674 WriteFile(HeaderName, std::string(HeaderTop) + HeaderBottom);675 676 ClangTU = clang_parseTranslationUnit(Index, CppName.c_str(), nullptr, 0,677 nullptr, 0, TUFlags);678 EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU));679 DisplayDiagnostics();680 681 // Immedaitely reparse.682 ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */));683 EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU));684 685 std::string NewHeaderContents =686 std::string(HeaderTop) + "int baz;" + HeaderBottom;687 WriteFile(HeaderName, NewHeaderContents);688 689 // Reparse after fix.690 ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */));691 EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU));692}693 694TEST_F(LibclangReparseTest, ReparseWithModule) {695 const char *HeaderTop = "#ifndef H\n#define H\nstruct Foo { int bar;";696 const char *HeaderBottom = "\n};\n#endif\n";697 const char *MFile = "#include \"HeaderFile.h\"\nint main() {"698 " struct Foo foo; foo.bar = 7; foo.baz = 8; }\n";699 const char *ModFile = "module A { header \"HeaderFile.h\" }\n";700 std::string HeaderName = "HeaderFile.h";701 std::string MName = "MFile.m";702 std::string ModName = "module.modulemap";703 WriteFile(MName, MFile);704 WriteFile(HeaderName, std::string(HeaderTop) + HeaderBottom);705 WriteFile(ModName, ModFile);706 707 // Removing recursively is necessary to delete the module cache.708 RemoveTestDirRecursivelyDuringTeardown = true;709 std::string ModulesCache = std::string("-fmodules-cache-path=") + TestDir;710 const char *Args[] = { "-fmodules", ModulesCache.c_str(),711 "-I", TestDir.c_str() };712 int NumArgs = std::size(Args);713 ClangTU = clang_parseTranslationUnit(Index, MName.c_str(), Args, NumArgs,714 nullptr, 0, TUFlags);715 EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU));716 DisplayDiagnostics();717 718 // Immedaitely reparse.719 ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */));720 EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU));721 722 std::string NewHeaderContents =723 std::string(HeaderTop) + "int baz;" + HeaderBottom;724 WriteFile(HeaderName, NewHeaderContents);725 726 // Reparse after fix.727 ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */));728 EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU));729}730 731TEST_F(LibclangReparseTest, clang_parseTranslationUnit2FullArgv) {732 // Provide a fake GCC 99.9.9 standard library that always overrides any local733 // GCC installation.734 std::string EmptyFiles[] = {"lib/gcc/arm-linux-gnueabi/99.9.9/crtbegin.o",735 "include/arm-linux-gnueabi/.keep",736 "include/c++/99.9.9/vector"};737 738 for (auto &Name : EmptyFiles)739 WriteFile(Name, "\n");740 741 std::string Filename = "test.cc";742 WriteFile(Filename, "#include <vector>\n");743 744 std::string Clang = "bin/clang";745 WriteFile(Clang, "");746 747 const char *Argv[] = {Clang.c_str(), "-target", "arm-linux-gnueabi",748 "-stdlib=libstdc++", "--gcc-toolchain="};749 750 EXPECT_EQ(CXError_Success,751 clang_parseTranslationUnit2FullArgv(Index, Filename.c_str(), Argv,752 std::size(Argv),753 nullptr, 0, TUFlags, &ClangTU));754 EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU));755 DisplayDiagnostics();756}757 758class LibclangPrintingPolicyTest : public LibclangParseTest {759public:760 CXPrintingPolicy Policy = nullptr;761 762 void SetUp() override {763 LibclangParseTest::SetUp();764 std::string File = "file.cpp";765 WriteFile(File, "int i;\n");766 ClangTU = clang_parseTranslationUnit(Index, File.c_str(), nullptr, 0,767 nullptr, 0, TUFlags);768 CXCursor TUCursor = clang_getTranslationUnitCursor(ClangTU);769 Policy = clang_getCursorPrintingPolicy(TUCursor);770 }771 void TearDown() override {772 clang_PrintingPolicy_dispose(Policy);773 LibclangParseTest::TearDown();774 }775};776 777TEST_F(LibclangPrintingPolicyTest, SetAndGetProperties) {778 for (unsigned Value = 0; Value < 2; ++Value) {779 for (int I = 0; I < CXPrintingPolicy_LastProperty; ++I) {780 auto Property = static_cast<enum CXPrintingPolicyProperty>(I);781 782 clang_PrintingPolicy_setProperty(Policy, Property, Value);783 EXPECT_EQ(Value, clang_PrintingPolicy_getProperty(Policy, Property));784 }785 }786}787 788TEST_F(LibclangReparseTest, PreprocessorSkippedRanges) {789 std::string Header = "header.h", Main = "main.cpp";790 WriteFile(Header,791 "#ifdef MANGOS\n"792 "printf(\"mmm\");\n"793 "#endif");794 WriteFile(Main,795 "#include \"header.h\"\n"796 "#ifdef GUAVA\n"797 "#endif\n"798 "#ifdef KIWIS\n"799 "printf(\"mmm!!\");\n"800 "#endif");801 802 for (int i = 0; i != 3; ++i) {803 unsigned flags = TUFlags | CXTranslationUnit_PrecompiledPreamble;804 if (i == 2)805 flags |= CXTranslationUnit_CreatePreambleOnFirstParse;806 807 if (i != 0)808 clang_disposeTranslationUnit(ClangTU); // dispose from previous iter809 810 // parse once811 ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0,812 nullptr, 0, flags);813 if (i != 0) {814 // reparse815 ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */));816 }817 818 // Check all ranges are there819 CXSourceRangeList *Ranges = clang_getAllSkippedRanges(ClangTU);820 EXPECT_EQ(3U, Ranges->count);821 822 CXSourceLocation cxl;823 unsigned line;824 cxl = clang_getRangeStart(Ranges->ranges[0]);825 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);826 EXPECT_EQ(1U, line);827 cxl = clang_getRangeEnd(Ranges->ranges[0]);828 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);829 EXPECT_EQ(3U, line);830 831 cxl = clang_getRangeStart(Ranges->ranges[1]);832 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);833 EXPECT_EQ(2U, line);834 cxl = clang_getRangeEnd(Ranges->ranges[1]);835 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);836 EXPECT_EQ(3U, line);837 838 cxl = clang_getRangeStart(Ranges->ranges[2]);839 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);840 EXPECT_EQ(4U, line);841 cxl = clang_getRangeEnd(Ranges->ranges[2]);842 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);843 EXPECT_EQ(6U, line);844 845 clang_disposeSourceRangeList(Ranges);846 847 // Check obtaining ranges by each file works848 CXFile cxf = clang_getFile(ClangTU, Header.c_str());849 Ranges = clang_getSkippedRanges(ClangTU, cxf);850 EXPECT_EQ(1U, Ranges->count);851 cxl = clang_getRangeStart(Ranges->ranges[0]);852 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);853 EXPECT_EQ(1U, line);854 clang_disposeSourceRangeList(Ranges);855 856 cxf = clang_getFile(ClangTU, Main.c_str());857 Ranges = clang_getSkippedRanges(ClangTU, cxf);858 EXPECT_EQ(2U, Ranges->count);859 cxl = clang_getRangeStart(Ranges->ranges[0]);860 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);861 EXPECT_EQ(2U, line);862 cxl = clang_getRangeStart(Ranges->ranges[1]);863 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);864 EXPECT_EQ(4U, line);865 clang_disposeSourceRangeList(Ranges);866 }867}868 869class LibclangSerializationTest : public LibclangParseTest {870public:871 bool SaveAndLoadTU(const std::string &Filename) {872 unsigned options = clang_defaultSaveOptions(ClangTU);873 if (clang_saveTranslationUnit(ClangTU, Filename.c_str(), options) !=874 CXSaveError_None) {875 LLVM_DEBUG(llvm::dbgs() << "Saving failed\n");876 return false;877 }878 879 clang_disposeTranslationUnit(ClangTU);880 881 ClangTU = clang_createTranslationUnit(Index, Filename.c_str());882 883 if (!ClangTU) {884 LLVM_DEBUG(llvm::dbgs() << "Loading failed\n");885 return false;886 }887 888 return true;889 }890};891 892TEST_F(LibclangSerializationTest, TokenKindsAreCorrectAfterLoading) {893 // Ensure that "class" is recognized as a keyword token after serializing894 // and reloading the AST, as it is not a keyword for the default LangOptions.895 std::string HeaderName = "test.h";896 WriteFile(HeaderName, "enum class Something {};");897 898 const char *Argv[] = {"-xc++-header", "-std=c++11"};899 900 ClangTU = clang_parseTranslationUnit(Index, HeaderName.c_str(), Argv,901 std::size(Argv), nullptr,902 0, TUFlags);903 904 auto CheckTokenKinds = [=]() {905 CXSourceRange Range =906 clang_getCursorExtent(clang_getTranslationUnitCursor(ClangTU));907 908 CXToken *Tokens;909 unsigned int NumTokens;910 clang_tokenize(ClangTU, Range, &Tokens, &NumTokens);911 912 ASSERT_EQ(6u, NumTokens);913 EXPECT_EQ(CXToken_Keyword, clang_getTokenKind(Tokens[0]));914 EXPECT_EQ(CXToken_Keyword, clang_getTokenKind(Tokens[1]));915 EXPECT_EQ(CXToken_Identifier, clang_getTokenKind(Tokens[2]));916 EXPECT_EQ(CXToken_Punctuation, clang_getTokenKind(Tokens[3]));917 EXPECT_EQ(CXToken_Punctuation, clang_getTokenKind(Tokens[4]));918 EXPECT_EQ(CXToken_Punctuation, clang_getTokenKind(Tokens[5]));919 920 clang_disposeTokens(ClangTU, Tokens, NumTokens);921 };922 923 CheckTokenKinds();924 925 std::string ASTName = "test.ast";926 WriteFile(ASTName, "");927 928 ASSERT_TRUE(SaveAndLoadTU(ASTName));929 930 CheckTokenKinds();931}932 933TEST_F(LibclangParseTest, clang_getVarDeclInitializer) {934 std::string Main = "main.cpp";935 WriteFile(Main, "int foo() { return 5; }; const int a = foo();");936 ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, nullptr,937 0, TUFlags);938 939 CXCursor C = clang_getTranslationUnitCursor(ClangTU);940 clang_visitChildren(941 C,942 [](CXCursor cursor, CXCursor parent,943 CXClientData client_data) -> CXChildVisitResult {944 if (clang_getCursorKind(cursor) == CXCursor_VarDecl) {945 const CXCursor Initializer = clang_Cursor_getVarDeclInitializer(cursor);946 EXPECT_FALSE(clang_Cursor_isNull(Initializer));947 CXString Spelling = clang_getCursorSpelling(Initializer);948 const char* const SpellingCSstr = clang_getCString(Spelling);949 EXPECT_TRUE(SpellingCSstr);950 EXPECT_EQ(std::string(SpellingCSstr), std::string("foo"));951 clang_disposeString(Spelling);952 return CXChildVisit_Break;953 }954 return CXChildVisit_Continue;955 },956 nullptr);957}958 959TEST_F(LibclangParseTest, clang_hasVarDeclGlobalStorageFalse) {960 std::string Main = "main.cpp";961 WriteFile(Main, "void foo() { int a; }");962 ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, nullptr,963 0, TUFlags);964 965 CXCursor C = clang_getTranslationUnitCursor(ClangTU);966 clang_visitChildren(967 C,968 [](CXCursor cursor, CXCursor parent,969 CXClientData client_data) -> CXChildVisitResult {970 if (clang_getCursorKind(cursor) == CXCursor_VarDecl) {971 EXPECT_FALSE(clang_Cursor_hasVarDeclGlobalStorage(cursor));972 return CXChildVisit_Break;973 }974 return CXChildVisit_Continue;975 },976 nullptr);977}978 979TEST_F(LibclangParseTest, clang_Cursor_hasVarDeclGlobalStorageTrue) {980 std::string Main = "main.cpp";981 WriteFile(Main, "int a;");982 ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, nullptr,983 0, TUFlags);984 985 CXCursor C = clang_getTranslationUnitCursor(ClangTU);986 clang_visitChildren(987 C,988 [](CXCursor cursor, CXCursor parent,989 CXClientData client_data) -> CXChildVisitResult {990 if (clang_getCursorKind(cursor) == CXCursor_VarDecl) {991 EXPECT_TRUE(clang_Cursor_hasVarDeclGlobalStorage(cursor));992 return CXChildVisit_Break;993 }994 return CXChildVisit_Continue;995 },996 nullptr);997}998 999TEST_F(LibclangParseTest, clang_Cursor_hasVarDeclExternalStorageFalse) {1000 std::string Main = "main.cpp";1001 WriteFile(Main, "int a;");1002 ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, nullptr,1003 0, TUFlags);1004 1005 CXCursor C = clang_getTranslationUnitCursor(ClangTU);1006 clang_visitChildren(1007 C,1008 [](CXCursor cursor, CXCursor parent,1009 CXClientData client_data) -> CXChildVisitResult {1010 if (clang_getCursorKind(cursor) == CXCursor_VarDecl) {1011 EXPECT_FALSE(clang_Cursor_hasVarDeclExternalStorage(cursor));1012 return CXChildVisit_Break;1013 }1014 return CXChildVisit_Continue;1015 },1016 nullptr);1017}1018 1019TEST_F(LibclangParseTest, clang_Cursor_hasVarDeclExternalStorageTrue) {1020 std::string Main = "main.cpp";1021 WriteFile(Main, "extern int a;");1022 ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, nullptr,1023 0, TUFlags);1024 1025 CXCursor C = clang_getTranslationUnitCursor(ClangTU);1026 clang_visitChildren(1027 C,1028 [](CXCursor cursor, CXCursor parent,1029 CXClientData client_data) -> CXChildVisitResult {1030 if (clang_getCursorKind(cursor) == CXCursor_VarDecl) {1031 EXPECT_TRUE(clang_Cursor_hasVarDeclExternalStorage(cursor));1032 return CXChildVisit_Break;1033 }1034 return CXChildVisit_Continue;1035 },1036 nullptr);1037}1038 1039TEST_F(LibclangParseTest, clang_getUnqualifiedTypeRemovesQualifiers) {1040 std::string Header = "header.h";1041 WriteFile(Header, "void foo1(const int);\n"1042 "void foo2(volatile int);\n"1043 "void foo3(const volatile int);\n"1044 "void foo4(int* const);\n"1045 "void foo5(int* volatile);\n"1046 "void foo6(int* restrict);\n"1047 "void foo7(int* const volatile);\n"1048 "void foo8(int* volatile restrict);\n"1049 "void foo9(int* const restrict);\n"1050 "void foo10(int* const volatile restrict);\n");1051 1052 auto is_qualified = [](CXType type) -> bool {1053 return clang_isConstQualifiedType(type) ||1054 clang_isVolatileQualifiedType(type) ||1055 clang_isRestrictQualifiedType(type);1056 };1057 1058 ClangTU = clang_parseTranslationUnit(Index, Header.c_str(), nullptr, 0,1059 nullptr, 0, TUFlags);1060 1061 Traverse([&is_qualified](CXCursor cursor, CXCursor) {1062 if (clang_getCursorKind(cursor) == CXCursor_FunctionDecl) {1063 CXType arg_type = clang_getArgType(clang_getCursorType(cursor), 0);1064 EXPECT_TRUE(is_qualified(arg_type))1065 << "Input data '" << fromCXString(clang_getCursorSpelling(cursor))1066 << "' first argument does not have a qualified type.";1067 1068 CXType unqualified_arg_type = clang_getUnqualifiedType(arg_type);1069 EXPECT_FALSE(is_qualified(unqualified_arg_type))1070 << "The type '" << fromCXString(clang_getTypeSpelling(arg_type))1071 << "' was not unqualified after a call to clang_getUnqualifiedType.";1072 }1073 1074 return CXChildVisit_Continue;1075 });1076}1077 1078TEST_F(LibclangParseTest, clang_getNonReferenceTypeRemovesRefQualifiers) {1079 std::string Header = "header.h";1080 WriteFile(Header, "void foo1(int&);\n"1081 "void foo2(int&&);\n");1082 1083 auto is_ref_qualified = [](CXType type) -> bool {1084 return (type.kind == CXType_LValueReference) ||1085 (type.kind == CXType_RValueReference);1086 };1087 1088 const char *Args[] = {"-xc++"};1089 ClangTU = clang_parseTranslationUnit(Index, Header.c_str(), Args, 1, nullptr,1090 0, TUFlags);1091 1092 Traverse([&is_ref_qualified](CXCursor cursor, CXCursor) {1093 if (clang_getCursorKind(cursor) == CXCursor_FunctionDecl) {1094 CXType arg_type = clang_getArgType(clang_getCursorType(cursor), 0);1095 EXPECT_TRUE(is_ref_qualified(arg_type))1096 << "Input data '" << fromCXString(clang_getCursorSpelling(cursor))1097 << "' first argument does not have a ref-qualified type.";1098 1099 CXType non_reference_arg_type = clang_getNonReferenceType(arg_type);1100 EXPECT_FALSE(is_ref_qualified(non_reference_arg_type))1101 << "The type '" << fromCXString(clang_getTypeSpelling(arg_type))1102 << "' ref-qualifier was not removed after a call to "1103 "clang_getNonReferenceType.";1104 }1105 1106 return CXChildVisit_Continue;1107 });1108}1109 1110TEST_F(LibclangParseTest, VisitUsingTypeLoc) {1111 const char testSource[] = R"cpp(1112namespace ns1 {1113class Class11114{1115 void fun();1116};1117}1118 1119using ns1::Class1;1120 1121void Class1::fun() {}1122)cpp";1123 std::string fileName = "main.cpp";1124 WriteFile(fileName, testSource);1125 const char *Args[] = {"-xc++"};1126 ClangTU = clang_parseTranslationUnit(Index, fileName.c_str(), Args, 1,1127 nullptr, 0, TUFlags);1128 1129 std::optional<CXCursor> typeRefCsr;1130 Traverse([&](CXCursor cursor, CXCursor parent) -> CXChildVisitResult {1131 if (cursor.kind == CXCursor_TypeRef) {1132 typeRefCsr.emplace(cursor);1133 }1134 return CXChildVisit_Recurse;1135 });1136 ASSERT_TRUE(typeRefCsr.has_value());1137 EXPECT_EQ(fromCXString(clang_getCursorSpelling(*typeRefCsr)),1138 "class ns1::Class1");1139}1140 1141TEST_F(LibclangParseTest, BinaryOperator) {1142 std::string Main = "main.cpp";1143 WriteFile(Main, "int foo() { return 5 + 9; }");1144 ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, nullptr,1145 0, TUFlags);1146 1147 Traverse([](CXCursor cursor, CXCursor parent) -> CXChildVisitResult {1148 if (cursor.kind == CXCursor_BinaryOperator) {1149 EXPECT_EQ(clang_getCursorBinaryOperatorKind(cursor),1150 CXBinaryOperator_Add);1151 return CXChildVisit_Break;1152 }1153 1154 return CXChildVisit_Recurse;1155 });1156}1157 1158TEST_F(LibclangParseTest, UnaryOperator) {1159 std::string Main = "main.cpp";1160 WriteFile(Main, "int foo() { int a = 5; return a++; }");1161 ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, nullptr,1162 0, TUFlags);1163 1164 Traverse([](CXCursor cursor, CXCursor parent) -> CXChildVisitResult {1165 if (cursor.kind == CXCursor_UnaryOperator) {1166 EXPECT_EQ(clang_getCursorUnaryOperatorKind(cursor),1167 CXUnaryOperator_PostInc);1168 return CXChildVisit_Break;1169 }1170 1171 return CXChildVisit_Recurse;1172 });1173}1174 1175TEST_F(LibclangParseTest, VisitStaticAssertDecl_noMessage) {1176 const char testSource[] = R"cpp(static_assert(true))cpp";1177 std::string fileName = "main.cpp";1178 WriteFile(fileName, testSource);1179 const char *Args[] = {"-xc++"};1180 ClangTU = clang_parseTranslationUnit(Index, fileName.c_str(), Args, 1,1181 nullptr, 0, TUFlags);1182 1183 std::optional<CXCursor> staticAssertCsr;1184 Traverse([&](CXCursor cursor, CXCursor parent) -> CXChildVisitResult {1185 if (cursor.kind == CXCursor_StaticAssert) {1186 staticAssertCsr.emplace(cursor);1187 return CXChildVisit_Break;1188 }1189 return CXChildVisit_Recurse;1190 });1191 ASSERT_TRUE(staticAssertCsr.has_value());1192 Traverse(*staticAssertCsr, [](CXCursor cursor, CXCursor parent) {1193 EXPECT_EQ(cursor.kind, CXCursor_CXXBoolLiteralExpr);1194 return CXChildVisit_Break;1195 });1196 EXPECT_EQ(fromCXString(clang_getCursorSpelling(*staticAssertCsr)), "");1197}1198 1199TEST_F(LibclangParseTest, VisitStaticAssertDecl_exprMessage) {1200 const char testSource[] = R"cpp(1201template <unsigned s>1202constexpr unsigned size(const char (&)[s])1203{1204 return s - 1;1205}1206 1207struct Message {1208 static constexpr char message[] = "Hello World!";1209 constexpr const char* data() const { return message;}1210 constexpr unsigned size() const1211 {1212 return ::size(message);1213 }1214};1215Message message;1216static_assert(true, message);1217)cpp";1218 std::string fileName = "main.cpp";1219 WriteFile(fileName, testSource);1220 const char *Args[] = {"-xc++", "-std=c++26"};1221 ClangTU = clang_parseTranslationUnit(Index, fileName.c_str(), Args,1222 std::size(Args), nullptr, 0, TUFlags);1223 ASSERT_EQ(clang_getNumDiagnostics(ClangTU), 0u);1224 std::optional<CXCursor> staticAssertCsr;1225 Traverse([&](CXCursor cursor, CXCursor parent) -> CXChildVisitResult {1226 if (cursor.kind == CXCursor_StaticAssert) {1227 staticAssertCsr.emplace(cursor);1228 }1229 return CXChildVisit_Continue;1230 });1231 ASSERT_TRUE(staticAssertCsr.has_value());1232 int argCnt = 0;1233 Traverse(*staticAssertCsr, [&argCnt](CXCursor cursor, CXCursor parent) {1234 switch (argCnt) {1235 case 0:1236 EXPECT_EQ(cursor.kind, CXCursor_CXXBoolLiteralExpr);1237 break;1238 case 1:1239 EXPECT_EQ(cursor.kind, CXCursor_DeclRefExpr);1240 break;1241 }1242 ++argCnt;1243 return CXChildVisit_Continue;1244 });1245 ASSERT_EQ(argCnt, 2);1246 EXPECT_EQ(fromCXString(clang_getCursorSpelling(*staticAssertCsr)), "");1247}1248 1249TEST_F(LibclangParseTest, ExposesAnnotateArgs) {1250 const char testSource[] = R"cpp(1251[[clang::annotate("category", 42)]]1252void func() {}1253)cpp";1254 std::string fileName = "main.cpp";1255 WriteFile(fileName, testSource);1256 1257 const char *Args[] = {"-xc++"};1258 ClangTU = clang_parseTranslationUnit(Index, fileName.c_str(), Args, 1,1259 nullptr, 0, TUFlags);1260 1261 int attrCount = 0;1262 1263 Traverse(1264 [&attrCount](CXCursor cursor, CXCursor parent) -> CXChildVisitResult {1265 if (cursor.kind == CXCursor_AnnotateAttr) {1266 int childCount = 0;1267 clang_visitChildren(1268 cursor,1269 [](CXCursor child, CXCursor,1270 CXClientData data) -> CXChildVisitResult {1271 int *pcount = static_cast<int *>(data);1272 1273 // we only expect one argument here, so bail otherwise1274 EXPECT_EQ(*pcount, 0);1275 1276 auto *result = clang_Cursor_Evaluate(child);1277 EXPECT_NE(result, nullptr);1278 EXPECT_EQ(clang_EvalResult_getAsInt(result), 42);1279 clang_EvalResult_dispose(result);1280 1281 ++*pcount;1282 1283 return CXChildVisit_Recurse;1284 },1285 &childCount);1286 attrCount++;1287 return CXChildVisit_Continue;1288 }1289 return CXChildVisit_Recurse;1290 });1291 1292 EXPECT_EQ(attrCount, 1);1293}1294 1295TEST_F(LibclangParseTest, clang_getSpellingLocation) {1296 std::string fileName = "main.c";1297 WriteFile(fileName, "#define X(value) int x = value;\nX(42)\n");1298 1299 ClangTU = clang_parseTranslationUnit(Index, fileName.c_str(), nullptr, 0,1300 nullptr, 0, TUFlags);1301 1302 int declarationCount = 0;1303 Traverse([&declarationCount](CXCursor cursor,1304 CXCursor parent) -> CXChildVisitResult {1305 if (cursor.kind == CXCursor_VarDecl) {1306 declarationCount++;1307 1308 CXSourceLocation cxl = clang_getCursorLocation(cursor);1309 unsigned line;1310 1311 // We expect clang_getFileLocation to return the expansion location,1312 // whereas clang_getSpellingLocation should resolve the macro expansion1313 // and return the location of the macro definition.1314 clang_getFileLocation(cxl, nullptr, &line, nullptr, nullptr);1315 EXPECT_EQ(line, 2U);1316 clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);1317 EXPECT_EQ(line, 1U);1318 }1319 1320 return CXChildVisit_Recurse;1321 });1322 1323 EXPECT_EQ(declarationCount, 1);1324}1325 1326class LibclangRewriteTest : public LibclangParseTest {1327public:1328 CXRewriter Rew = nullptr;1329 std::string Filename;1330 CXFile File = nullptr;1331 1332 void SetUp() override {1333 LibclangParseTest::SetUp();1334 Filename = "file.cpp";1335 WriteFile(Filename, "int main() { return 0; }");1336 ClangTU = clang_parseTranslationUnit(Index, Filename.c_str(), nullptr, 0,1337 nullptr, 0, TUFlags);1338 Rew = clang_CXRewriter_create(ClangTU);1339 File = clang_getFile(ClangTU, Filename.c_str());1340 }1341 void TearDown() override {1342 clang_CXRewriter_dispose(Rew);1343 LibclangParseTest::TearDown();1344 }1345};1346 1347static std::string getFileContent(const std::string& Filename) {1348 std::ifstream RewrittenFile(Filename);1349 std::string RewrittenFileContent;1350 std::string Line;1351 while (std::getline(RewrittenFile, Line)) {1352 if (RewrittenFileContent.empty())1353 RewrittenFileContent = Line;1354 else {1355 RewrittenFileContent += "\n" + Line;1356 }1357 }1358 return RewrittenFileContent;1359}1360 1361TEST_F(LibclangRewriteTest, RewriteReplace) {1362 CXSourceLocation B = clang_getLocation(ClangTU, File, 1, 5);1363 CXSourceLocation E = clang_getLocation(ClangTU, File, 1, 9);1364 CXSourceRange Rng = clang_getRange(B, E);1365 1366 clang_CXRewriter_replaceText(Rew, Rng, "MAIN");1367 1368 ASSERT_EQ(clang_CXRewriter_overwriteChangedFiles(Rew), 0);1369 EXPECT_EQ(getFileContent(Filename), "int MAIN() { return 0; }");1370}1371 1372TEST_F(LibclangRewriteTest, RewriteReplaceShorter) {1373 CXSourceLocation B = clang_getLocation(ClangTU, File, 1, 5);1374 CXSourceLocation E = clang_getLocation(ClangTU, File, 1, 9);1375 CXSourceRange Rng = clang_getRange(B, E);1376 1377 clang_CXRewriter_replaceText(Rew, Rng, "foo");1378 1379 ASSERT_EQ(clang_CXRewriter_overwriteChangedFiles(Rew), 0);1380 EXPECT_EQ(getFileContent(Filename), "int foo() { return 0; }");1381}1382 1383TEST_F(LibclangRewriteTest, RewriteReplaceLonger) {1384 CXSourceLocation B = clang_getLocation(ClangTU, File, 1, 5);1385 CXSourceLocation E = clang_getLocation(ClangTU, File, 1, 9);1386 CXSourceRange Rng = clang_getRange(B, E);1387 1388 clang_CXRewriter_replaceText(Rew, Rng, "patatino");1389 1390 ASSERT_EQ(clang_CXRewriter_overwriteChangedFiles(Rew), 0);1391 EXPECT_EQ(getFileContent(Filename), "int patatino() { return 0; }");1392}1393 1394TEST_F(LibclangRewriteTest, RewriteInsert) {1395 CXSourceLocation Loc = clang_getLocation(ClangTU, File, 1, 5);1396 1397 clang_CXRewriter_insertTextBefore(Rew, Loc, "ro");1398 1399 ASSERT_EQ(clang_CXRewriter_overwriteChangedFiles(Rew), 0);1400 EXPECT_EQ(getFileContent(Filename), "int romain() { return 0; }");1401}1402 1403TEST_F(LibclangRewriteTest, RewriteRemove) {1404 CXSourceLocation B = clang_getLocation(ClangTU, File, 1, 5);1405 CXSourceLocation E = clang_getLocation(ClangTU, File, 1, 9);1406 CXSourceRange Rng = clang_getRange(B, E);1407 1408 clang_CXRewriter_removeText(Rew, Rng);1409 1410 ASSERT_EQ(clang_CXRewriter_overwriteChangedFiles(Rew), 0);1411 EXPECT_EQ(getFileContent(Filename), "int () { return 0; }");1412}1413 1414TEST_F(LibclangParseTest, FileEqual) {1415 std::string AInc = "a.inc", BInc = "b.inc", Main = "main.cpp";1416 WriteFile(Main, "int a[] = {\n"1417 " #include \"a.inc\"\n"1418 "};\n"1419 "int b[] = {\n"1420 " #include \"b.inc\"\n"1421 "};");1422 WriteFile(AInc, "1,2,3");1423 WriteFile(BInc, "1,2,3");1424 1425 ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, nullptr,1426 0, TUFlags);1427 1428 CXFile AFile = clang_getFile(ClangTU, AInc.c_str()),1429 AFile2 = clang_getFile(ClangTU, AInc.c_str()),1430 BFile = clang_getFile(ClangTU, BInc.c_str()),1431 MainFile = clang_getFile(ClangTU, Main.c_str());1432 1433 ASSERT_FALSE(clang_File_isEqual(MainFile, AFile));1434 ASSERT_FALSE(clang_File_isEqual(AFile, BFile));1435 ASSERT_TRUE(clang_File_isEqual(AFile, AFile2));1436}1437 1438TEST_F(LibclangParseTest, FileEqualInMemory) {1439 std::string AInc = "a.inc", BInc = "b.inc", Main = "main.cpp";1440 MapUnsavedFile(Main, "int a[] = {\n"1441 " #include \"a.inc\"\n"1442 "};\n"1443 "int b[] = {\n"1444 " #include \"b.inc\"\n"1445 "};");1446 MapUnsavedFile(AInc, "1,2,3");1447 MapUnsavedFile(BInc, "1,2,3");1448 1449 ClangTU = clang_parseTranslationUnit(Index, UnsavedFiles[0].Filename, nullptr,1450 0, &UnsavedFiles.front(),1451 UnsavedFiles.size(), TUFlags);1452 1453 CXFile AFile = clang_getFile(ClangTU, UnsavedFiles[1].Filename),1454 AFile2 = clang_getFile(ClangTU, UnsavedFiles[1].Filename),1455 BFile = clang_getFile(ClangTU, UnsavedFiles[2].Filename),1456 MainFile = clang_getFile(ClangTU, UnsavedFiles[0].Filename);1457 1458 ASSERT_FALSE(clang_File_isEqual(MainFile, AFile));1459 ASSERT_FALSE(clang_File_isEqual(AFile, BFile));1460 ASSERT_TRUE(clang_File_isEqual(AFile, AFile2));1461}1462