brintos

brintos / llvm-project-archived public Read only

0
0
Text · 47.9 KiB · b2a87d2 Raw
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