xref: /llvm-project/clang/unittests/libclang/LibclangTest.cpp (revision 2e770edd8ce13f48402f1d93e5fb982d8a2ebe64)
1 //===- unittests/libclang/LibclangTest.cpp --- libclang tests -------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "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 
TEST(libclang,clang_parseTranslationUnit2_InvalidArgs)27 TEST(libclang, clang_parseTranslationUnit2_InvalidArgs) {
28   EXPECT_EQ(CXError_InvalidArguments,
29             clang_parseTranslationUnit2(nullptr, nullptr, nullptr, 0, nullptr,
30                                         0, 0, nullptr));
31 }
32 
TEST(libclang,clang_createTranslationUnit_InvalidArgs)33 TEST(libclang, clang_createTranslationUnit_InvalidArgs) {
34   EXPECT_EQ(nullptr, clang_createTranslationUnit(nullptr, nullptr));
35 }
36 
TEST(libclang,clang_createTranslationUnit2_InvalidArgs)37 TEST(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 
47 namespace {
48 struct TestVFO {
49   const char *Contents;
50   CXVirtualFileOverlay VFO;
51 
TestVFO__anon6ab2deb00111::TestVFO52   TestVFO(const char *Contents) : Contents(Contents) {
53     VFO = clang_VirtualFileOverlay_create(0);
54   }
55 
map__anon6ab2deb00111::TestVFO56   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 
mapError__anon6ab2deb00111::TestVFO61   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 
~TestVFO__anon6ab2deb00111::TestVFO66   ~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 
TEST(libclang,VirtualFileOverlay_Basic)80 TEST(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 
TEST(libclang,VirtualFileOverlay_Unicode)102 TEST(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 
TEST(libclang,VirtualFileOverlay_InvalidArgs)124 TEST(libclang, VirtualFileOverlay_InvalidArgs) {
125   TestVFO T(nullptr);
126   T.mapError("/path/./virtual/../foo.h", "/real/foo.h",
127              CXError_InvalidArguments);
128 }
129 
TEST(libclang,VirtualFileOverlay_RemapDirectories)130 TEST(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 
TEST(libclang,VirtualFileOverlay_CaseInsensitive)182 TEST(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 
TEST(libclang,VirtualFileOverlay_SharedPrefix)206 TEST(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 
TEST(libclang,VirtualFileOverlay_AdjacentDirectory)258 TEST(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 
TEST(libclang,VirtualFileOverlay_TopLevel)304 TEST(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 
TEST(libclang,VirtualFileOverlay_Empty)326 TEST(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 
TEST(libclang,ModuleMapDescriptor)336 TEST(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 
TEST_F(LibclangParseTest,GlobalOptions)359 TEST_F(LibclangParseTest, GlobalOptions) {
360   EXPECT_EQ(clang_CXIndex_getGlobalOptions(Index), CXGlobalOpt_None);
361 }
362 
363 class LibclangIndexOptionsTest : public LibclangParseTest {
AdjustOptions(CXIndexOptions & Opts)364   virtual void AdjustOptions(CXIndexOptions &Opts) {}
365 
366 protected:
CreateIndex()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 
TEST_F(LibclangIndexOptionsTest,GlobalOptions)377 TEST_F(LibclangIndexOptionsTest, GlobalOptions) {
378   EXPECT_EQ(clang_CXIndex_getGlobalOptions(Index), CXGlobalOpt_None);
379 }
380 
381 class LibclangIndexingEnabledIndexOptionsTest
382     : public LibclangIndexOptionsTest {
AdjustOptions(CXIndexOptions & Opts)383   void AdjustOptions(CXIndexOptions &Opts) override {
384     Opts.ThreadBackgroundPriorityForIndexing = CXChoice_Enabled;
385   }
386 };
387 
TEST_F(LibclangIndexingEnabledIndexOptionsTest,GlobalOptions)388 TEST_F(LibclangIndexingEnabledIndexOptionsTest, GlobalOptions) {
389   EXPECT_EQ(clang_CXIndex_getGlobalOptions(Index),
390             CXGlobalOpt_ThreadBackgroundPriorityForIndexing);
391 }
392 
393 class LibclangIndexingDisabledEditingEnabledIndexOptionsTest
394     : public LibclangIndexOptionsTest {
AdjustOptions(CXIndexOptions & Opts)395   void AdjustOptions(CXIndexOptions &Opts) override {
396     Opts.ThreadBackgroundPriorityForIndexing = CXChoice_Disabled;
397     Opts.ThreadBackgroundPriorityForEditing = CXChoice_Enabled;
398   }
399 };
400 
TEST_F(LibclangIndexingDisabledEditingEnabledIndexOptionsTest,GlobalOptions)401 TEST_F(LibclangIndexingDisabledEditingEnabledIndexOptionsTest, GlobalOptions) {
402   EXPECT_EQ(clang_CXIndex_getGlobalOptions(Index),
403             CXGlobalOpt_ThreadBackgroundPriorityForEditing);
404 }
405 
406 class LibclangBothEnabledIndexOptionsTest : public LibclangIndexOptionsTest {
AdjustOptions(CXIndexOptions & Opts)407   void AdjustOptions(CXIndexOptions &Opts) override {
408     Opts.ThreadBackgroundPriorityForIndexing = CXChoice_Enabled;
409     Opts.ThreadBackgroundPriorityForEditing = CXChoice_Enabled;
410   }
411 };
412 
TEST_F(LibclangBothEnabledIndexOptionsTest,GlobalOptions)413 TEST_F(LibclangBothEnabledIndexOptionsTest, GlobalOptions) {
414   EXPECT_EQ(clang_CXIndex_getGlobalOptions(Index),
415             CXGlobalOpt_ThreadBackgroundPriorityForAll);
416 }
417 
418 class LibclangPreambleStorageTest : public LibclangParseTest {
419   std::string Main = "main.cpp";
420 
421 protected:
422   std::string PreambleDir;
InitializePreambleDir()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 
433 public:
CountPreamblesInPreambleDir(int PreambleCount)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 is
461         // created with default permissions and replaces the .pch file along
462         // with its permissions. Therefore the permissions set in
463         // 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 
472 class LibclangNotOverriddenPreambleStoragePathTest
473     : public LibclangPreambleStorageTest {
474 protected:
CreateIndex()475   void CreateIndex() override {
476     InitializePreambleDir();
477     LibclangPreambleStorageTest::CreateIndex();
478   }
479 };
480 
481 class LibclangSetPreambleStoragePathTest : public LibclangPreambleStorageTest {
StorePreamblesInMemory()482   virtual bool StorePreamblesInMemory() { return false; }
483   virtual const char *PreambleStoragePath() = 0;
484 
485 protected:
CreateIndex()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 
498 class LibclangNullPreambleStoragePathTest
499     : public LibclangSetPreambleStoragePathTest {
PreambleStoragePath()500   const char *PreambleStoragePath() override { return nullptr; }
501 };
502 class LibclangEmptyPreambleStoragePathTest
503     : public LibclangSetPreambleStoragePathTest {
PreambleStoragePath()504   const char *PreambleStoragePath() override { return ""; }
505 };
506 class LibclangPreambleDirPreambleStoragePathTest
507     : public LibclangSetPreambleStoragePathTest {
PreambleStoragePath()508   const char *PreambleStoragePath() override { return PreambleDir.c_str(); }
509 };
510 
511 class LibclangStoreInMemoryNullPreambleStoragePathTest
512     : public LibclangNullPreambleStoragePathTest {
StorePreamblesInMemory()513   bool StorePreamblesInMemory() override { return true; }
514 };
515 class LibclangStoreInMemoryEmptyPreambleStoragePathTest
516     : public LibclangEmptyPreambleStoragePathTest {
StorePreamblesInMemory()517   bool StorePreamblesInMemory() override { return true; }
518 };
519 class LibclangStoreInMemoryPreambleDirPreambleStoragePathTest
520     : public LibclangPreambleDirPreambleStoragePathTest {
StorePreamblesInMemory()521   bool StorePreamblesInMemory() override { return true; }
522 };
523 
TEST_F(LibclangNotOverriddenPreambleStoragePathTest,CountPreambles)524 TEST_F(LibclangNotOverriddenPreambleStoragePathTest, CountPreambles) {
525   CountPreamblesInPreambleDir(0);
526 }
TEST_F(LibclangNullPreambleStoragePathTest,CountPreambles)527 TEST_F(LibclangNullPreambleStoragePathTest, CountPreambles) {
528   CountPreamblesInPreambleDir(0);
529 }
TEST_F(LibclangEmptyPreambleStoragePathTest,CountPreambles)530 TEST_F(LibclangEmptyPreambleStoragePathTest, CountPreambles) {
531   CountPreamblesInPreambleDir(0);
532 }
TEST_F(LibclangPreambleDirPreambleStoragePathTest,CountPreambles)533 TEST_F(LibclangPreambleDirPreambleStoragePathTest, CountPreambles) {
534   CountPreamblesInPreambleDir(1);
535 }
TEST_F(LibclangStoreInMemoryNullPreambleStoragePathTest,CountPreambles)536 TEST_F(LibclangStoreInMemoryNullPreambleStoragePathTest, CountPreambles) {
537   CountPreamblesInPreambleDir(0);
538 }
TEST_F(LibclangStoreInMemoryEmptyPreambleStoragePathTest,CountPreambles)539 TEST_F(LibclangStoreInMemoryEmptyPreambleStoragePathTest, CountPreambles) {
540   CountPreamblesInPreambleDir(0);
541 }
TEST_F(LibclangStoreInMemoryPreambleDirPreambleStoragePathTest,CountPreambles)542 TEST_F(LibclangStoreInMemoryPreambleDirPreambleStoragePathTest,
543        CountPreambles) {
544   CountPreamblesInPreambleDir(0);
545 }
546 
TEST_F(LibclangParseTest,AllSkippedRanges)547 TEST_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 
TEST_F(LibclangParseTest,EvaluateChildExpression)584 TEST_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 
626 class LibclangReparseTest : public LibclangParseTest {
627 public:
DisplayDiagnostics()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   }
ReparseTU(unsigned num_unsaved_files,CXUnsavedFile * unsaved_files)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 
TEST_F(LibclangReparseTest,FileName)650 TEST_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 
TEST_F(LibclangReparseTest,Reparse)666 TEST_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 
TEST_F(LibclangReparseTest,ReparseWithModule)694 TEST_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 
TEST_F(LibclangReparseTest,clang_parseTranslationUnit2FullArgv)731 TEST_F(LibclangReparseTest, clang_parseTranslationUnit2FullArgv) {
732   // Provide a fake GCC 99.9.9 standard library that always overrides any local
733   // 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 
758 class LibclangPrintingPolicyTest : public LibclangParseTest {
759 public:
760   CXPrintingPolicy Policy = nullptr;
761 
SetUp()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   }
TearDown()771   void TearDown() override {
772     clang_PrintingPolicy_dispose(Policy);
773     LibclangParseTest::TearDown();
774   }
775 };
776 
TEST_F(LibclangPrintingPolicyTest,SetAndGetProperties)777 TEST_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 
TEST_F(LibclangReparseTest,PreprocessorSkippedRanges)788 TEST_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 iter
809 
810     // parse once
811     ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0,
812                                          nullptr, 0, flags);
813     if (i != 0) {
814       // reparse
815       ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */));
816     }
817 
818     // Check all ranges are there
819     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 works
848     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 
869 class LibclangSerializationTest : public LibclangParseTest {
870 public:
SaveAndLoadTU(const std::string & Filename)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 
TEST_F(LibclangSerializationTest,TokenKindsAreCorrectAfterLoading)892 TEST_F(LibclangSerializationTest, TokenKindsAreCorrectAfterLoading) {
893   // Ensure that "class" is recognized as a keyword token after serializing
894   // 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 
TEST_F(LibclangParseTest,clang_getVarDeclInitializer)933 TEST_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 
TEST_F(LibclangParseTest,clang_hasVarDeclGlobalStorageFalse)959 TEST_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 
TEST_F(LibclangParseTest,clang_Cursor_hasVarDeclGlobalStorageTrue)979 TEST_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 
TEST_F(LibclangParseTest,clang_Cursor_hasVarDeclExternalStorageFalse)999 TEST_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 
TEST_F(LibclangParseTest,clang_Cursor_hasVarDeclExternalStorageTrue)1019 TEST_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 
TEST_F(LibclangParseTest,clang_getUnqualifiedTypeRemovesQualifiers)1039 TEST_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 
TEST_F(LibclangParseTest,clang_getNonReferenceTypeRemovesRefQualifiers)1078 TEST_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 
TEST_F(LibclangParseTest,VisitUsingTypeLoc)1110 TEST_F(LibclangParseTest, VisitUsingTypeLoc) {
1111   const char testSource[] = R"cpp(
1112 namespace ns1 {
1113 class Class1
1114 {
1115     void fun();
1116 };
1117 }
1118 
1119 using ns1::Class1;
1120 
1121 void 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 
TEST_F(LibclangParseTest,BinaryOperator)1141 TEST_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 
TEST_F(LibclangParseTest,UnaryOperator)1158 TEST_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 
TEST_F(LibclangParseTest,VisitStaticAssertDecl_noMessage)1175 TEST_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 
TEST_F(LibclangParseTest,VisitStaticAssertDecl_exprMessage)1199 TEST_F(LibclangParseTest, VisitStaticAssertDecl_exprMessage) {
1200   const char testSource[] = R"cpp(
1201 template <unsigned s>
1202 constexpr unsigned size(const char (&)[s])
1203 {
1204     return s - 1;
1205 }
1206 
1207 struct Message {
1208     static constexpr char message[] = "Hello World!";
1209     constexpr const char* data() const { return message;}
1210     constexpr unsigned size() const
1211     {
1212         return ::size(message);
1213     }
1214 };
1215 Message message;
1216 static_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 
TEST_F(LibclangParseTest,ExposesAnnotateArgs)1249 TEST_F(LibclangParseTest, ExposesAnnotateArgs) {
1250   const char testSource[] = R"cpp(
1251 [[clang::annotate("category", 42)]]
1252 void 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 otherwise
1274                 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 
TEST_F(LibclangParseTest,clang_getSpellingLocation)1295 TEST_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 expansion
1313       // 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 
1326 class LibclangRewriteTest : public LibclangParseTest {
1327 public:
1328   CXRewriter Rew = nullptr;
1329   std::string Filename;
1330   CXFile File = nullptr;
1331 
SetUp()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   }
TearDown()1341   void TearDown() override {
1342     clang_CXRewriter_dispose(Rew);
1343     LibclangParseTest::TearDown();
1344   }
1345 };
1346 
getFileContent(const std::string & Filename)1347 static 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 
TEST_F(LibclangRewriteTest,RewriteReplace)1361 TEST_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 
TEST_F(LibclangRewriteTest,RewriteReplaceShorter)1372 TEST_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 
TEST_F(LibclangRewriteTest,RewriteReplaceLonger)1383 TEST_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 
TEST_F(LibclangRewriteTest,RewriteInsert)1394 TEST_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 
TEST_F(LibclangRewriteTest,RewriteRemove)1403 TEST_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