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