xref: /llvm-project/clang/unittests/libclang/LibclangTest.cpp (revision 3eceab95f314edb85ee72c047a4acd35e757d037)
1 //===- unittests/libclang/LibclangTest.cpp --- libclang tests -------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "clang-c/Index.h"
10 #include "clang-c/Rewrite.h"
11 #include "llvm/ADT/StringRef.h"
12 #include "llvm/Support/Debug.h"
13 #include "llvm/Support/FileSystem.h"
14 #include "llvm/Support/Path.h"
15 #include "llvm/Support/raw_ostream.h"
16 #include "gtest/gtest.h"
17 #include "TestUtils.h"
18 #include <fstream>
19 #include <functional>
20 #include <map>
21 #include <memory>
22 #include <optional>
23 #include <set>
24 #define DEBUG_TYPE "libclang-test"
25 
26 TEST(libclang, clang_parseTranslationUnit2_InvalidArgs) {
27   EXPECT_EQ(CXError_InvalidArguments,
28             clang_parseTranslationUnit2(nullptr, nullptr, nullptr, 0, nullptr,
29                                         0, 0, nullptr));
30 }
31 
32 TEST(libclang, clang_createTranslationUnit_InvalidArgs) {
33   EXPECT_EQ(nullptr, clang_createTranslationUnit(nullptr, nullptr));
34 }
35 
36 TEST(libclang, clang_createTranslationUnit2_InvalidArgs) {
37   EXPECT_EQ(CXError_InvalidArguments,
38             clang_createTranslationUnit2(nullptr, nullptr, nullptr));
39 
40   CXTranslationUnit TU = reinterpret_cast<CXTranslationUnit>(1);
41   EXPECT_EQ(CXError_InvalidArguments,
42             clang_createTranslationUnit2(nullptr, nullptr, &TU));
43   EXPECT_EQ(nullptr, TU);
44 }
45 
46 namespace {
47 struct TestVFO {
48   const char *Contents;
49   CXVirtualFileOverlay VFO;
50 
51   TestVFO(const char *Contents) : Contents(Contents) {
52     VFO = clang_VirtualFileOverlay_create(0);
53   }
54 
55   void map(const char *VPath, const char *RPath) {
56     CXErrorCode Err = clang_VirtualFileOverlay_addFileMapping(VFO, VPath, RPath);
57     EXPECT_EQ(Err, CXError_Success);
58   }
59 
60   void mapError(const char *VPath, const char *RPath, CXErrorCode ExpErr) {
61     CXErrorCode Err = clang_VirtualFileOverlay_addFileMapping(VFO, VPath, RPath);
62     EXPECT_EQ(Err, ExpErr);
63   }
64 
65   ~TestVFO() {
66     if (Contents) {
67       char *BufPtr;
68       unsigned BufSize;
69       clang_VirtualFileOverlay_writeToBuffer(VFO, 0, &BufPtr, &BufSize);
70       std::string BufStr(BufPtr, BufSize);
71       EXPECT_STREQ(Contents, BufStr.c_str());
72       clang_free(BufPtr);
73     }
74     clang_VirtualFileOverlay_dispose(VFO);
75   }
76 };
77 }
78 
79 TEST(libclang, VirtualFileOverlay_Basic) {
80   const char *contents =
81       "{\n"
82       "  'version': 0,\n"
83       "  'roots': [\n"
84       "    {\n"
85       "      'type': 'directory',\n"
86       "      'name': \"/path/virtual\",\n"
87       "      'contents': [\n"
88       "        {\n"
89       "          'type': 'file',\n"
90       "          'name': \"foo.h\",\n"
91       "          'external-contents': \"/real/foo.h\"\n"
92       "        }\n"
93       "      ]\n"
94       "    }\n"
95       "  ]\n"
96       "}\n";
97   TestVFO T(contents);
98   T.map("/path/virtual/foo.h", "/real/foo.h");
99 }
100 
101 TEST(libclang, VirtualFileOverlay_Unicode) {
102   const char *contents =
103       "{\n"
104       "  'version': 0,\n"
105       "  'roots': [\n"
106       "    {\n"
107       "      'type': 'directory',\n"
108       "      'name': \"/path/\\u266B\",\n"
109       "      'contents': [\n"
110       "        {\n"
111       "          'type': 'file',\n"
112       "          'name': \"\\u2602.h\",\n"
113       "          'external-contents': \"/real/\\u2602.h\"\n"
114       "        }\n"
115       "      ]\n"
116       "    }\n"
117       "  ]\n"
118       "}\n";
119   TestVFO T(contents);
120   T.map("/path/♫/☂.h", "/real/☂.h");
121 }
122 
123 TEST(libclang, VirtualFileOverlay_InvalidArgs) {
124   TestVFO T(nullptr);
125   T.mapError("/path/./virtual/../foo.h", "/real/foo.h",
126              CXError_InvalidArguments);
127 }
128 
129 TEST(libclang, VirtualFileOverlay_RemapDirectories) {
130   const char *contents =
131       "{\n"
132       "  'version': 0,\n"
133       "  'roots': [\n"
134       "    {\n"
135       "      'type': 'directory',\n"
136       "      'name': \"/another/dir\",\n"
137       "      'contents': [\n"
138       "        {\n"
139       "          'type': 'file',\n"
140       "          'name': \"foo2.h\",\n"
141       "          'external-contents': \"/real/foo2.h\"\n"
142       "        }\n"
143       "      ]\n"
144       "    },\n"
145       "    {\n"
146       "      'type': 'directory',\n"
147       "      'name': \"/path/virtual/dir\",\n"
148       "      'contents': [\n"
149       "        {\n"
150       "          'type': 'file',\n"
151       "          'name': \"foo1.h\",\n"
152       "          'external-contents': \"/real/foo1.h\"\n"
153       "        },\n"
154       "        {\n"
155       "          'type': 'file',\n"
156       "          'name': \"foo3.h\",\n"
157       "          'external-contents': \"/real/foo3.h\"\n"
158       "        },\n"
159       "        {\n"
160       "          'type': 'directory',\n"
161       "          'name': \"in/subdir\",\n"
162       "          'contents': [\n"
163       "            {\n"
164       "              'type': 'file',\n"
165       "              'name': \"foo4.h\",\n"
166       "              'external-contents': \"/real/foo4.h\"\n"
167       "            }\n"
168       "          ]\n"
169       "        }\n"
170       "      ]\n"
171       "    }\n"
172       "  ]\n"
173       "}\n";
174   TestVFO T(contents);
175   T.map("/path/virtual/dir/foo1.h", "/real/foo1.h");
176   T.map("/another/dir/foo2.h", "/real/foo2.h");
177   T.map("/path/virtual/dir/foo3.h", "/real/foo3.h");
178   T.map("/path/virtual/dir/in/subdir/foo4.h", "/real/foo4.h");
179 }
180 
181 TEST(libclang, VirtualFileOverlay_CaseInsensitive) {
182   const char *contents =
183       "{\n"
184       "  'version': 0,\n"
185       "  'case-sensitive': 'false',\n"
186       "  'roots': [\n"
187       "    {\n"
188       "      'type': 'directory',\n"
189       "      'name': \"/path/virtual\",\n"
190       "      'contents': [\n"
191       "        {\n"
192       "          'type': 'file',\n"
193       "          'name': \"foo.h\",\n"
194       "          'external-contents': \"/real/foo.h\"\n"
195       "        }\n"
196       "      ]\n"
197       "    }\n"
198       "  ]\n"
199       "}\n";
200   TestVFO T(contents);
201   T.map("/path/virtual/foo.h", "/real/foo.h");
202   clang_VirtualFileOverlay_setCaseSensitivity(T.VFO, false);
203 }
204 
205 TEST(libclang, VirtualFileOverlay_SharedPrefix) {
206   const char *contents =
207       "{\n"
208       "  'version': 0,\n"
209       "  'roots': [\n"
210       "    {\n"
211       "      'type': 'directory',\n"
212       "      'name': \"/path/foo\",\n"
213       "      'contents': [\n"
214       "        {\n"
215       "          'type': 'file',\n"
216       "          'name': \"bar\",\n"
217       "          'external-contents': \"/real/bar\"\n"
218       "        },\n"
219       "        {\n"
220       "          'type': 'file',\n"
221       "          'name': \"bar.h\",\n"
222       "          'external-contents': \"/real/bar.h\"\n"
223       "        }\n"
224       "      ]\n"
225       "    },\n"
226       "    {\n"
227       "      'type': 'directory',\n"
228       "      'name': \"/path/foobar\",\n"
229       "      'contents': [\n"
230       "        {\n"
231       "          'type': 'file',\n"
232       "          'name': \"baz.h\",\n"
233       "          'external-contents': \"/real/baz.h\"\n"
234       "        }\n"
235       "      ]\n"
236       "    },\n"
237       "    {\n"
238       "      'type': 'directory',\n"
239       "      'name': \"/path\",\n"
240       "      'contents': [\n"
241       "        {\n"
242       "          'type': 'file',\n"
243       "          'name': \"foobarbaz.h\",\n"
244       "          'external-contents': \"/real/foobarbaz.h\"\n"
245       "        }\n"
246       "      ]\n"
247       "    }\n"
248       "  ]\n"
249       "}\n";
250   TestVFO T(contents);
251   T.map("/path/foo/bar.h", "/real/bar.h");
252   T.map("/path/foo/bar", "/real/bar");
253   T.map("/path/foobar/baz.h", "/real/baz.h");
254   T.map("/path/foobarbaz.h", "/real/foobarbaz.h");
255 }
256 
257 TEST(libclang, VirtualFileOverlay_AdjacentDirectory) {
258   const char *contents =
259       "{\n"
260       "  'version': 0,\n"
261       "  'roots': [\n"
262       "    {\n"
263       "      'type': 'directory',\n"
264       "      'name': \"/path/dir1\",\n"
265       "      'contents': [\n"
266       "        {\n"
267       "          'type': 'file',\n"
268       "          'name': \"foo.h\",\n"
269       "          'external-contents': \"/real/foo.h\"\n"
270       "        },\n"
271       "        {\n"
272       "          'type': 'directory',\n"
273       "          'name': \"subdir\",\n"
274       "          'contents': [\n"
275       "            {\n"
276       "              'type': 'file',\n"
277       "              'name': \"bar.h\",\n"
278       "              'external-contents': \"/real/bar.h\"\n"
279       "            }\n"
280       "          ]\n"
281       "        }\n"
282       "      ]\n"
283       "    },\n"
284       "    {\n"
285       "      'type': 'directory',\n"
286       "      'name': \"/path/dir2\",\n"
287       "      'contents': [\n"
288       "        {\n"
289       "          'type': 'file',\n"
290       "          'name': \"baz.h\",\n"
291       "          'external-contents': \"/real/baz.h\"\n"
292       "        }\n"
293       "      ]\n"
294       "    }\n"
295       "  ]\n"
296       "}\n";
297   TestVFO T(contents);
298   T.map("/path/dir1/foo.h", "/real/foo.h");
299   T.map("/path/dir1/subdir/bar.h", "/real/bar.h");
300   T.map("/path/dir2/baz.h", "/real/baz.h");
301 }
302 
303 TEST(libclang, VirtualFileOverlay_TopLevel) {
304   const char *contents =
305       "{\n"
306       "  'version': 0,\n"
307       "  'roots': [\n"
308       "    {\n"
309       "      'type': 'directory',\n"
310       "      'name': \"/\",\n"
311       "      'contents': [\n"
312       "        {\n"
313       "          'type': 'file',\n"
314       "          'name': \"foo.h\",\n"
315       "          'external-contents': \"/real/foo.h\"\n"
316       "        }\n"
317       "      ]\n"
318       "    }\n"
319       "  ]\n"
320       "}\n";
321   TestVFO T(contents);
322   T.map("/foo.h", "/real/foo.h");
323 }
324 
325 TEST(libclang, VirtualFileOverlay_Empty) {
326   const char *contents =
327       "{\n"
328       "  'version': 0,\n"
329       "  'roots': [\n"
330       "  ]\n"
331       "}\n";
332   TestVFO T(contents);
333 }
334 
335 TEST(libclang, ModuleMapDescriptor) {
336   const char *Contents =
337     "framework module TestFrame {\n"
338     "  umbrella header \"TestFrame.h\"\n"
339     "\n"
340     "  export *\n"
341     "  module * { export * }\n"
342     "}\n";
343 
344   CXModuleMapDescriptor MMD = clang_ModuleMapDescriptor_create(0);
345 
346   clang_ModuleMapDescriptor_setFrameworkModuleName(MMD, "TestFrame");
347   clang_ModuleMapDescriptor_setUmbrellaHeader(MMD, "TestFrame.h");
348 
349   char *BufPtr;
350   unsigned BufSize;
351   clang_ModuleMapDescriptor_writeToBuffer(MMD, 0, &BufPtr, &BufSize);
352   std::string BufStr(BufPtr, BufSize);
353   EXPECT_STREQ(Contents, BufStr.c_str());
354   clang_free(BufPtr);
355   clang_ModuleMapDescriptor_dispose(MMD);
356 }
357 
358 TEST_F(LibclangParseTest, AllSkippedRanges) {
359   std::string Header = "header.h", Main = "main.cpp";
360   WriteFile(Header,
361     "#ifdef MANGOS\n"
362     "printf(\"mmm\");\n"
363     "#endif");
364   WriteFile(Main,
365     "#include \"header.h\"\n"
366     "#ifdef KIWIS\n"
367     "printf(\"mmm!!\");\n"
368     "#endif");
369 
370   ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0,
371                                        nullptr, 0, TUFlags);
372 
373   CXSourceRangeList *Ranges = clang_getAllSkippedRanges(ClangTU);
374   EXPECT_EQ(2U, Ranges->count);
375 
376   CXSourceLocation cxl;
377   unsigned line;
378   cxl = clang_getRangeStart(Ranges->ranges[0]);
379   clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);
380   EXPECT_EQ(1U, line);
381   cxl = clang_getRangeEnd(Ranges->ranges[0]);
382   clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);
383   EXPECT_EQ(3U, line);
384 
385   cxl = clang_getRangeStart(Ranges->ranges[1]);
386   clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);
387   EXPECT_EQ(2U, line);
388   cxl = clang_getRangeEnd(Ranges->ranges[1]);
389   clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);
390   EXPECT_EQ(4U, line);
391 
392   clang_disposeSourceRangeList(Ranges);
393 }
394 
395 TEST_F(LibclangParseTest, EvaluateChildExpression) {
396   std::string Main = "main.m";
397   WriteFile(Main, "#define kFOO @\"foo\"\n"
398                   "void foobar(void) {\n"
399                   " {kFOO;}\n"
400                   "}\n");
401   ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, nullptr,
402                                        0, TUFlags);
403 
404   CXCursor C = clang_getTranslationUnitCursor(ClangTU);
405   clang_visitChildren(
406       C,
407       [](CXCursor cursor, CXCursor parent,
408          CXClientData client_data) -> CXChildVisitResult {
409         if (clang_getCursorKind(cursor) == CXCursor_FunctionDecl) {
410           int numberedStmt = 0;
411           clang_visitChildren(
412               cursor,
413               [](CXCursor cursor, CXCursor parent,
414                  CXClientData client_data) -> CXChildVisitResult {
415                 int &numberedStmt = *((int *)client_data);
416                 if (clang_getCursorKind(cursor) == CXCursor_CompoundStmt) {
417                   if (numberedStmt) {
418                     CXEvalResult RE = clang_Cursor_Evaluate(cursor);
419                     EXPECT_NE(RE, nullptr);
420                     EXPECT_EQ(clang_EvalResult_getKind(RE),
421                               CXEval_ObjCStrLiteral);
422                     clang_EvalResult_dispose(RE);
423                     return CXChildVisit_Break;
424                   }
425                   numberedStmt++;
426                 }
427                 return CXChildVisit_Recurse;
428               },
429               &numberedStmt);
430           EXPECT_EQ(numberedStmt, 1);
431         }
432         return CXChildVisit_Continue;
433       },
434       nullptr);
435 }
436 
437 class LibclangReparseTest : public LibclangParseTest {
438 public:
439   void DisplayDiagnostics() {
440     unsigned NumDiagnostics = clang_getNumDiagnostics(ClangTU);
441     for (unsigned i = 0; i < NumDiagnostics; ++i) {
442       auto Diag = clang_getDiagnostic(ClangTU, i);
443       LLVM_DEBUG(llvm::dbgs()
444                  << clang_getCString(clang_formatDiagnostic(
445                         Diag, clang_defaultDiagnosticDisplayOptions()))
446                  << "\n");
447       clang_disposeDiagnostic(Diag);
448     }
449   }
450   bool ReparseTU(unsigned num_unsaved_files, CXUnsavedFile* unsaved_files) {
451     if (clang_reparseTranslationUnit(ClangTU, num_unsaved_files, unsaved_files,
452                                      clang_defaultReparseOptions(ClangTU))) {
453       LLVM_DEBUG(llvm::dbgs() << "Reparse failed\n");
454       return false;
455     }
456     DisplayDiagnostics();
457     return true;
458   }
459 };
460 
461 TEST_F(LibclangReparseTest, FileName) {
462   std::string CppName = "main.cpp";
463   WriteFile(CppName, "int main() {}");
464   ClangTU = clang_parseTranslationUnit(Index, CppName.c_str(), nullptr, 0,
465                                        nullptr, 0, TUFlags);
466   CXFile cxf = clang_getFile(ClangTU, CppName.c_str());
467 
468   CXString cxname = clang_getFileName(cxf);
469   ASSERT_STREQ(clang_getCString(cxname), CppName.c_str());
470   clang_disposeString(cxname);
471 
472   cxname = clang_File_tryGetRealPathName(cxf);
473   ASSERT_TRUE(llvm::StringRef(clang_getCString(cxname)).endswith("main.cpp"));
474   clang_disposeString(cxname);
475 }
476 
477 TEST_F(LibclangReparseTest, Reparse) {
478   const char *HeaderTop = "#ifndef H\n#define H\nstruct Foo { int bar;";
479   const char *HeaderBottom = "\n};\n#endif\n";
480   const char *CppFile = "#include \"HeaderFile.h\"\nint main() {"
481                          " Foo foo; foo.bar = 7; foo.baz = 8; }\n";
482   std::string HeaderName = "HeaderFile.h";
483   std::string CppName = "CppFile.cpp";
484   WriteFile(CppName, CppFile);
485   WriteFile(HeaderName, std::string(HeaderTop) + HeaderBottom);
486 
487   ClangTU = clang_parseTranslationUnit(Index, CppName.c_str(), nullptr, 0,
488                                        nullptr, 0, TUFlags);
489   EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU));
490   DisplayDiagnostics();
491 
492   // Immedaitely reparse.
493   ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */));
494   EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU));
495 
496   std::string NewHeaderContents =
497       std::string(HeaderTop) + "int baz;" + HeaderBottom;
498   WriteFile(HeaderName, NewHeaderContents);
499 
500   // Reparse after fix.
501   ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */));
502   EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU));
503 }
504 
505 TEST_F(LibclangReparseTest, ReparseWithModule) {
506   const char *HeaderTop = "#ifndef H\n#define H\nstruct Foo { int bar;";
507   const char *HeaderBottom = "\n};\n#endif\n";
508   const char *MFile = "#include \"HeaderFile.h\"\nint main() {"
509                          " struct Foo foo; foo.bar = 7; foo.baz = 8; }\n";
510   const char *ModFile = "module A { header \"HeaderFile.h\" }\n";
511   std::string HeaderName = "HeaderFile.h";
512   std::string MName = "MFile.m";
513   std::string ModName = "module.modulemap";
514   WriteFile(MName, MFile);
515   WriteFile(HeaderName, std::string(HeaderTop) + HeaderBottom);
516   WriteFile(ModName, ModFile);
517 
518   // Removing recursively is necessary to delete the module cache.
519   RemoveTestDirRecursivelyDuringTeardown = true;
520   std::string ModulesCache = std::string("-fmodules-cache-path=") + TestDir;
521   const char *Args[] = { "-fmodules", ModulesCache.c_str(),
522                          "-I", TestDir.c_str() };
523   int NumArgs = std::size(Args);
524   ClangTU = clang_parseTranslationUnit(Index, MName.c_str(), Args, NumArgs,
525                                        nullptr, 0, TUFlags);
526   EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU));
527   DisplayDiagnostics();
528 
529   // Immedaitely reparse.
530   ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */));
531   EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU));
532 
533   std::string NewHeaderContents =
534       std::string(HeaderTop) + "int baz;" + HeaderBottom;
535   WriteFile(HeaderName, NewHeaderContents);
536 
537   // Reparse after fix.
538   ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */));
539   EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU));
540 }
541 
542 TEST_F(LibclangReparseTest, clang_parseTranslationUnit2FullArgv) {
543   // Provide a fake GCC 99.9.9 standard library that always overrides any local
544   // GCC installation.
545   std::string EmptyFiles[] = {"lib/gcc/arm-linux-gnueabi/99.9.9/crtbegin.o",
546                               "include/arm-linux-gnueabi/.keep",
547                               "include/c++/99.9.9/vector"};
548 
549   for (auto &Name : EmptyFiles)
550     WriteFile(Name, "\n");
551 
552   std::string Filename = "test.cc";
553   WriteFile(Filename, "#include <vector>\n");
554 
555   std::string Clang = "bin/clang";
556   WriteFile(Clang, "");
557 
558   const char *Argv[] = {Clang.c_str(), "-target", "arm-linux-gnueabi",
559                         "-stdlib=libstdc++", "--gcc-toolchain="};
560 
561   EXPECT_EQ(CXError_Success,
562             clang_parseTranslationUnit2FullArgv(Index, Filename.c_str(), Argv,
563                                                 std::size(Argv),
564                                                 nullptr, 0, TUFlags, &ClangTU));
565   EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU));
566   DisplayDiagnostics();
567 }
568 
569 class LibclangPrintingPolicyTest : public LibclangParseTest {
570 public:
571   CXPrintingPolicy Policy = nullptr;
572 
573   void SetUp() override {
574     LibclangParseTest::SetUp();
575     std::string File = "file.cpp";
576     WriteFile(File, "int i;\n");
577     ClangTU = clang_parseTranslationUnit(Index, File.c_str(), nullptr, 0,
578                                          nullptr, 0, TUFlags);
579     CXCursor TUCursor = clang_getTranslationUnitCursor(ClangTU);
580     Policy = clang_getCursorPrintingPolicy(TUCursor);
581   }
582   void TearDown() override {
583     clang_PrintingPolicy_dispose(Policy);
584     LibclangParseTest::TearDown();
585   }
586 };
587 
588 TEST_F(LibclangPrintingPolicyTest, SetAndGetProperties) {
589   for (unsigned Value = 0; Value < 2; ++Value) {
590     for (int I = 0; I < CXPrintingPolicy_LastProperty; ++I) {
591       auto Property = static_cast<enum CXPrintingPolicyProperty>(I);
592 
593       clang_PrintingPolicy_setProperty(Policy, Property, Value);
594       EXPECT_EQ(Value, clang_PrintingPolicy_getProperty(Policy, Property));
595     }
596   }
597 }
598 
599 TEST_F(LibclangReparseTest, PreprocessorSkippedRanges) {
600   std::string Header = "header.h", Main = "main.cpp";
601   WriteFile(Header,
602     "#ifdef MANGOS\n"
603     "printf(\"mmm\");\n"
604     "#endif");
605   WriteFile(Main,
606     "#include \"header.h\"\n"
607     "#ifdef GUAVA\n"
608     "#endif\n"
609     "#ifdef KIWIS\n"
610     "printf(\"mmm!!\");\n"
611     "#endif");
612 
613   for (int i = 0; i != 3; ++i) {
614     unsigned flags = TUFlags | CXTranslationUnit_PrecompiledPreamble;
615     if (i == 2)
616       flags |= CXTranslationUnit_CreatePreambleOnFirstParse;
617 
618     if (i != 0)
619        clang_disposeTranslationUnit(ClangTU);  // dispose from previous iter
620 
621     // parse once
622     ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0,
623                                          nullptr, 0, flags);
624     if (i != 0) {
625       // reparse
626       ASSERT_TRUE(ReparseTU(0, nullptr /* No unsaved files. */));
627     }
628 
629     // Check all ranges are there
630     CXSourceRangeList *Ranges = clang_getAllSkippedRanges(ClangTU);
631     EXPECT_EQ(3U, Ranges->count);
632 
633     CXSourceLocation cxl;
634     unsigned line;
635     cxl = clang_getRangeStart(Ranges->ranges[0]);
636     clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);
637     EXPECT_EQ(1U, line);
638     cxl = clang_getRangeEnd(Ranges->ranges[0]);
639     clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);
640     EXPECT_EQ(3U, line);
641 
642     cxl = clang_getRangeStart(Ranges->ranges[1]);
643     clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);
644     EXPECT_EQ(2U, line);
645     cxl = clang_getRangeEnd(Ranges->ranges[1]);
646     clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);
647     EXPECT_EQ(3U, line);
648 
649     cxl = clang_getRangeStart(Ranges->ranges[2]);
650     clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);
651     EXPECT_EQ(4U, line);
652     cxl = clang_getRangeEnd(Ranges->ranges[2]);
653     clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);
654     EXPECT_EQ(6U, line);
655 
656     clang_disposeSourceRangeList(Ranges);
657 
658     // Check obtaining ranges by each file works
659     CXFile cxf = clang_getFile(ClangTU, Header.c_str());
660     Ranges = clang_getSkippedRanges(ClangTU, cxf);
661     EXPECT_EQ(1U, Ranges->count);
662     cxl = clang_getRangeStart(Ranges->ranges[0]);
663     clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);
664     EXPECT_EQ(1U, line);
665     clang_disposeSourceRangeList(Ranges);
666 
667     cxf = clang_getFile(ClangTU, Main.c_str());
668     Ranges = clang_getSkippedRanges(ClangTU, cxf);
669     EXPECT_EQ(2U, Ranges->count);
670     cxl = clang_getRangeStart(Ranges->ranges[0]);
671     clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);
672     EXPECT_EQ(2U, line);
673     cxl = clang_getRangeStart(Ranges->ranges[1]);
674     clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);
675     EXPECT_EQ(4U, line);
676     clang_disposeSourceRangeList(Ranges);
677   }
678 }
679 
680 class LibclangSerializationTest : public LibclangParseTest {
681 public:
682   bool SaveAndLoadTU(const std::string &Filename) {
683     unsigned options = clang_defaultSaveOptions(ClangTU);
684     if (clang_saveTranslationUnit(ClangTU, Filename.c_str(), options) !=
685         CXSaveError_None) {
686       LLVM_DEBUG(llvm::dbgs() << "Saving failed\n");
687       return false;
688     }
689 
690     clang_disposeTranslationUnit(ClangTU);
691 
692     ClangTU = clang_createTranslationUnit(Index, Filename.c_str());
693 
694     if (!ClangTU) {
695       LLVM_DEBUG(llvm::dbgs() << "Loading failed\n");
696       return false;
697     }
698 
699     return true;
700   }
701 };
702 
703 TEST_F(LibclangSerializationTest, TokenKindsAreCorrectAfterLoading) {
704   // Ensure that "class" is recognized as a keyword token after serializing
705   // and reloading the AST, as it is not a keyword for the default LangOptions.
706   std::string HeaderName = "test.h";
707   WriteFile(HeaderName, "enum class Something {};");
708 
709   const char *Argv[] = {"-xc++-header", "-std=c++11"};
710 
711   ClangTU = clang_parseTranslationUnit(Index, HeaderName.c_str(), Argv,
712                                        std::size(Argv), nullptr,
713                                        0, TUFlags);
714 
715   auto CheckTokenKinds = [=]() {
716     CXSourceRange Range =
717         clang_getCursorExtent(clang_getTranslationUnitCursor(ClangTU));
718 
719     CXToken *Tokens;
720     unsigned int NumTokens;
721     clang_tokenize(ClangTU, Range, &Tokens, &NumTokens);
722 
723     ASSERT_EQ(6u, NumTokens);
724     EXPECT_EQ(CXToken_Keyword, clang_getTokenKind(Tokens[0]));
725     EXPECT_EQ(CXToken_Keyword, clang_getTokenKind(Tokens[1]));
726     EXPECT_EQ(CXToken_Identifier, clang_getTokenKind(Tokens[2]));
727     EXPECT_EQ(CXToken_Punctuation, clang_getTokenKind(Tokens[3]));
728     EXPECT_EQ(CXToken_Punctuation, clang_getTokenKind(Tokens[4]));
729     EXPECT_EQ(CXToken_Punctuation, clang_getTokenKind(Tokens[5]));
730 
731     clang_disposeTokens(ClangTU, Tokens, NumTokens);
732   };
733 
734   CheckTokenKinds();
735 
736   std::string ASTName = "test.ast";
737   WriteFile(ASTName, "");
738 
739   ASSERT_TRUE(SaveAndLoadTU(ASTName));
740 
741   CheckTokenKinds();
742 }
743 
744 TEST_F(LibclangParseTest, clang_getVarDeclInitializer) {
745   std::string Main = "main.cpp";
746   WriteFile(Main, "int foo() { return 5; }; const int a = foo();");
747   ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, nullptr,
748                                        0, TUFlags);
749 
750   CXCursor C = clang_getTranslationUnitCursor(ClangTU);
751   clang_visitChildren(
752       C,
753       [](CXCursor cursor, CXCursor parent,
754          CXClientData client_data) -> CXChildVisitResult {
755         if (clang_getCursorKind(cursor) == CXCursor_VarDecl) {
756           const CXCursor Initializer = clang_Cursor_getVarDeclInitializer(cursor);
757           EXPECT_FALSE(clang_Cursor_isNull(Initializer));
758           CXString Spelling = clang_getCursorSpelling(Initializer);
759           const char* const SpellingCSstr = clang_getCString(Spelling);
760           EXPECT_TRUE(SpellingCSstr);
761           EXPECT_EQ(std::string(SpellingCSstr), std::string("foo"));
762           clang_disposeString(Spelling);
763           return CXChildVisit_Break;
764         }
765         return CXChildVisit_Continue;
766       },
767       nullptr);
768 }
769 
770 TEST_F(LibclangParseTest, clang_hasVarDeclGlobalStorageFalse) {
771   std::string Main = "main.cpp";
772   WriteFile(Main, "void foo() { int a; }");
773   ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, nullptr,
774                                        0, TUFlags);
775 
776   CXCursor C = clang_getTranslationUnitCursor(ClangTU);
777   clang_visitChildren(
778       C,
779       [](CXCursor cursor, CXCursor parent,
780          CXClientData client_data) -> CXChildVisitResult {
781         if (clang_getCursorKind(cursor) == CXCursor_VarDecl) {
782           EXPECT_FALSE(clang_Cursor_hasVarDeclGlobalStorage(cursor));
783           return CXChildVisit_Break;
784         }
785         return CXChildVisit_Continue;
786       },
787       nullptr);
788 }
789 
790 TEST_F(LibclangParseTest, clang_Cursor_hasVarDeclGlobalStorageTrue) {
791   std::string Main = "main.cpp";
792   WriteFile(Main, "int a;");
793   ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, nullptr,
794                                        0, TUFlags);
795 
796   CXCursor C = clang_getTranslationUnitCursor(ClangTU);
797   clang_visitChildren(
798       C,
799       [](CXCursor cursor, CXCursor parent,
800          CXClientData client_data) -> CXChildVisitResult {
801         if (clang_getCursorKind(cursor) == CXCursor_VarDecl) {
802           EXPECT_TRUE(clang_Cursor_hasVarDeclGlobalStorage(cursor));
803           return CXChildVisit_Break;
804         }
805         return CXChildVisit_Continue;
806       },
807       nullptr);
808 }
809 
810 TEST_F(LibclangParseTest, clang_Cursor_hasVarDeclExternalStorageFalse) {
811   std::string Main = "main.cpp";
812   WriteFile(Main, "int a;");
813   ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, nullptr,
814                                        0, TUFlags);
815 
816   CXCursor C = clang_getTranslationUnitCursor(ClangTU);
817   clang_visitChildren(
818       C,
819       [](CXCursor cursor, CXCursor parent,
820          CXClientData client_data) -> CXChildVisitResult {
821         if (clang_getCursorKind(cursor) == CXCursor_VarDecl) {
822           EXPECT_FALSE(clang_Cursor_hasVarDeclExternalStorage(cursor));
823           return CXChildVisit_Break;
824         }
825         return CXChildVisit_Continue;
826       },
827       nullptr);
828 }
829 
830 TEST_F(LibclangParseTest, clang_Cursor_hasVarDeclExternalStorageTrue) {
831   std::string Main = "main.cpp";
832   WriteFile(Main, "extern int a;");
833   ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, nullptr,
834                                        0, TUFlags);
835 
836   CXCursor C = clang_getTranslationUnitCursor(ClangTU);
837   clang_visitChildren(
838       C,
839       [](CXCursor cursor, CXCursor parent,
840          CXClientData client_data) -> CXChildVisitResult {
841         if (clang_getCursorKind(cursor) == CXCursor_VarDecl) {
842           EXPECT_TRUE(clang_Cursor_hasVarDeclExternalStorage(cursor));
843           return CXChildVisit_Break;
844         }
845         return CXChildVisit_Continue;
846       },
847       nullptr);
848 }
849 
850 TEST_F(LibclangParseTest, clang_getUnqualifiedTypeRemovesQualifiers) {
851   std::string Header = "header.h";
852   WriteFile(Header, "void foo1(const int);\n"
853                     "void foo2(volatile int);\n"
854                     "void foo3(const volatile int);\n"
855                     "void foo4(int* const);\n"
856                     "void foo5(int* volatile);\n"
857                     "void foo6(int* restrict);\n"
858                     "void foo7(int* const volatile);\n"
859                     "void foo8(int* volatile restrict);\n"
860                     "void foo9(int* const restrict);\n"
861                     "void foo10(int* const volatile restrict);\n");
862 
863   auto is_qualified = [](CXType type) -> bool {
864     return clang_isConstQualifiedType(type) ||
865            clang_isVolatileQualifiedType(type) ||
866            clang_isRestrictQualifiedType(type);
867   };
868 
869   ClangTU = clang_parseTranslationUnit(Index, Header.c_str(), nullptr, 0,
870                                        nullptr, 0, TUFlags);
871 
872   Traverse([&is_qualified](CXCursor cursor, CXCursor) {
873     if (clang_getCursorKind(cursor) == CXCursor_FunctionDecl) {
874       CXType arg_type = clang_getArgType(clang_getCursorType(cursor), 0);
875       EXPECT_TRUE(is_qualified(arg_type))
876           << "Input data '" << fromCXString(clang_getCursorSpelling(cursor))
877           << "' first argument does not have a qualified type.";
878 
879       CXType unqualified_arg_type = clang_getUnqualifiedType(arg_type);
880       EXPECT_FALSE(is_qualified(unqualified_arg_type))
881           << "The type '" << fromCXString(clang_getTypeSpelling(arg_type))
882           << "' was not unqualified after a call to clang_getUnqualifiedType.";
883     }
884 
885     return CXChildVisit_Continue;
886   });
887 }
888 
889 TEST_F(LibclangParseTest, clang_getNonReferenceTypeRemovesRefQualifiers) {
890   std::string Header = "header.h";
891   WriteFile(Header, "void foo1(int&);\n"
892                     "void foo2(int&&);\n");
893 
894   auto is_ref_qualified = [](CXType type) -> bool {
895     return (type.kind == CXType_LValueReference) ||
896            (type.kind == CXType_RValueReference);
897   };
898 
899   const char *Args[] = {"-xc++"};
900   ClangTU = clang_parseTranslationUnit(Index, Header.c_str(), Args, 1, nullptr,
901                                        0, TUFlags);
902 
903   Traverse([&is_ref_qualified](CXCursor cursor, CXCursor) {
904     if (clang_getCursorKind(cursor) == CXCursor_FunctionDecl) {
905       CXType arg_type = clang_getArgType(clang_getCursorType(cursor), 0);
906       EXPECT_TRUE(is_ref_qualified(arg_type))
907           << "Input data '" << fromCXString(clang_getCursorSpelling(cursor))
908           << "' first argument does not have a ref-qualified type.";
909 
910       CXType non_reference_arg_type = clang_getNonReferenceType(arg_type);
911       EXPECT_FALSE(is_ref_qualified(non_reference_arg_type))
912           << "The type '" << fromCXString(clang_getTypeSpelling(arg_type))
913           << "' ref-qualifier was not removed after a call to "
914              "clang_getNonReferenceType.";
915     }
916 
917     return CXChildVisit_Continue;
918   });
919 }
920 
921 TEST_F(LibclangParseTest, VisitUsingTypeLoc) {
922   const char testSource[] = R"cpp(
923 namespace ns1 {
924 class Class1
925 {
926     void fun();
927 };
928 }
929 
930 using ns1::Class1;
931 
932 void Class1::fun() {}
933 )cpp";
934   std::string fileName = "main.cpp";
935   WriteFile(fileName, testSource);
936   const char *Args[] = {"-xc++"};
937   ClangTU = clang_parseTranslationUnit(Index, fileName.c_str(), Args, 1,
938                                        nullptr, 0, TUFlags);
939 
940   std::optional<CXCursor> typeRefCsr;
941   Traverse([&](CXCursor cursor, CXCursor parent) -> CXChildVisitResult {
942     if (cursor.kind == CXCursor_TypeRef) {
943       typeRefCsr.emplace(cursor);
944     }
945     return CXChildVisit_Recurse;
946   });
947   ASSERT_TRUE(typeRefCsr.has_value());
948   EXPECT_EQ(fromCXString(clang_getCursorSpelling(*typeRefCsr)),
949             "class ns1::Class1");
950 }
951 
952 class LibclangRewriteTest : public LibclangParseTest {
953 public:
954   CXRewriter Rew = nullptr;
955   std::string Filename;
956   CXFile File = nullptr;
957 
958   void SetUp() override {
959     LibclangParseTest::SetUp();
960     Filename = "file.cpp";
961     WriteFile(Filename, "int main() { return 0; }");
962     ClangTU = clang_parseTranslationUnit(Index, Filename.c_str(), nullptr, 0,
963                                          nullptr, 0, TUFlags);
964     Rew = clang_CXRewriter_create(ClangTU);
965     File = clang_getFile(ClangTU, Filename.c_str());
966   }
967   void TearDown() override {
968     clang_CXRewriter_dispose(Rew);
969     LibclangParseTest::TearDown();
970   }
971 };
972 
973 static std::string getFileContent(const std::string& Filename) {
974   std::ifstream RewrittenFile(Filename);
975   std::string RewrittenFileContent;
976   std::string Line;
977   while (std::getline(RewrittenFile, Line)) {
978     if (RewrittenFileContent.empty())
979       RewrittenFileContent = Line;
980     else {
981       RewrittenFileContent += "\n" + Line;
982     }
983   }
984   return RewrittenFileContent;
985 }
986 
987 TEST_F(LibclangRewriteTest, RewriteReplace) {
988   CXSourceLocation B = clang_getLocation(ClangTU, File, 1, 5);
989   CXSourceLocation E = clang_getLocation(ClangTU, File, 1, 9);
990   CXSourceRange Rng	= clang_getRange(B, E);
991 
992   clang_CXRewriter_replaceText(Rew, Rng, "MAIN");
993 
994   ASSERT_EQ(clang_CXRewriter_overwriteChangedFiles(Rew), 0);
995   EXPECT_EQ(getFileContent(Filename), "int MAIN() { return 0; }");
996 }
997 
998 TEST_F(LibclangRewriteTest, RewriteReplaceShorter) {
999   CXSourceLocation B = clang_getLocation(ClangTU, File, 1, 5);
1000   CXSourceLocation E = clang_getLocation(ClangTU, File, 1, 9);
1001   CXSourceRange Rng	= clang_getRange(B, E);
1002 
1003   clang_CXRewriter_replaceText(Rew, Rng, "foo");
1004 
1005   ASSERT_EQ(clang_CXRewriter_overwriteChangedFiles(Rew), 0);
1006   EXPECT_EQ(getFileContent(Filename), "int foo() { return 0; }");
1007 }
1008 
1009 TEST_F(LibclangRewriteTest, RewriteReplaceLonger) {
1010   CXSourceLocation B = clang_getLocation(ClangTU, File, 1, 5);
1011   CXSourceLocation E = clang_getLocation(ClangTU, File, 1, 9);
1012   CXSourceRange Rng	= clang_getRange(B, E);
1013 
1014   clang_CXRewriter_replaceText(Rew, Rng, "patatino");
1015 
1016   ASSERT_EQ(clang_CXRewriter_overwriteChangedFiles(Rew), 0);
1017   EXPECT_EQ(getFileContent(Filename), "int patatino() { return 0; }");
1018 }
1019 
1020 TEST_F(LibclangRewriteTest, RewriteInsert) {
1021   CXSourceLocation Loc = clang_getLocation(ClangTU, File, 1, 5);
1022 
1023   clang_CXRewriter_insertTextBefore(Rew, Loc, "ro");
1024 
1025   ASSERT_EQ(clang_CXRewriter_overwriteChangedFiles(Rew), 0);
1026   EXPECT_EQ(getFileContent(Filename), "int romain() { return 0; }");
1027 }
1028 
1029 TEST_F(LibclangRewriteTest, RewriteRemove) {
1030   CXSourceLocation B = clang_getLocation(ClangTU, File, 1, 5);
1031   CXSourceLocation E = clang_getLocation(ClangTU, File, 1, 9);
1032   CXSourceRange Rng	= clang_getRange(B, E);
1033 
1034   clang_CXRewriter_removeText(Rew, Rng);
1035 
1036   ASSERT_EQ(clang_CXRewriter_overwriteChangedFiles(Rew), 0);
1037   EXPECT_EQ(getFileContent(Filename), "int () { return 0; }");
1038 }
1039