Clang Project

clang_source_code/unittests/libclang/LibclangTest.cpp
1//===- unittests/libclang/LibclangTest.cpp --- libclang tests -------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "clang-c/Index.h"
10#include "llvm/ADT/StringRef.h"
11#include "llvm/Support/Debug.h"
12#include "llvm/Support/FileSystem.h"
13#include "llvm/Support/Path.h"
14#include "llvm/Support/raw_ostream.h"
15#include "gtest/gtest.h"
16#include <fstream>
17#include <functional>
18#include <map>
19#include <memory>
20#include <set>
21#define DEBUG_TYPE "libclang-test"
22
23TEST(libclang, clang_parseTranslationUnit2_InvalidArgs) {
24  EXPECT_EQ(CXError_InvalidArguments,
25            clang_parseTranslationUnit2(nullptrnullptrnullptr0nullptr,
26                                        00nullptr));
27}
28
29TEST(libclang, clang_createTranslationUnit_InvalidArgs) {
30  EXPECT_EQ(nullptrclang_createTranslationUnit(nullptrnullptr));
31}
32
33TEST(libclang, clang_createTranslationUnit2_InvalidArgs) {
34  EXPECT_EQ(CXError_InvalidArguments,
35            clang_createTranslationUnit2(nullptrnullptrnullptr));
36
37  CXTranslationUnit TU = reinterpret_cast<CXTranslationUnit>(1);
38  EXPECT_EQ(CXError_InvalidArguments,
39            clang_createTranslationUnit2(nullptrnullptr, &TU));
40  EXPECT_EQ(nullptrTU);
41}
42
43namespace {
44struct TestVFO {
45  const char *Contents;
46  CXVirtualFileOverlay VFO;
47
48  TestVFO(const char *Contents) : Contents(Contents) {
49    VFO = clang_VirtualFileOverlay_create(0);
50  }
51
52  void map(const char *VPathconst char *RPath) {
53    CXErrorCode Err = clang_VirtualFileOverlay_addFileMapping(VFOVPathRPath);
54    EXPECT_EQ(ErrCXError_Success);
55  }
56
57  void mapError(const char *VPathconst char *RPathCXErrorCode ExpErr) {
58    CXErrorCode Err = clang_VirtualFileOverlay_addFileMapping(VFOVPathRPath);
59    EXPECT_EQ(ErrExpErr);
60  }
61
62  ~TestVFO() {
63    if (Contents) {
64      char *BufPtr;
65      unsigned BufSize;
66      clang_VirtualFileOverlay_writeToBuffer(VFO0, &BufPtr, &BufSize);
67      std::string BufStr(BufPtrBufSize);
68      EXPECT_STREQ(ContentsBufStr.c_str());
69      clang_free(BufPtr);
70    }
71    clang_VirtualFileOverlay_dispose(VFO);
72  }
73};
74}
75
76TEST(libclang, VirtualFileOverlay_Basic) {
77  const char *contents =
78      "{\n"
79      "  'version': 0,\n"
80      "  'roots': [\n"
81      "    {\n"
82      "      'type': 'directory',\n"
83      "      'name': \"/path/virtual\",\n"
84      "      'contents': [\n"
85      "        {\n"
86      "          'type': 'file',\n"
87      "          'name': \"foo.h\",\n"
88      "          'external-contents': \"/real/foo.h\"\n"
89      "        }\n"
90      "      ]\n"
91      "    }\n"
92      "  ]\n"
93      "}\n";
94  TestVFO T(contents);
95  T.map("/path/virtual/foo.h""/real/foo.h");
96}
97
98TEST(libclang, VirtualFileOverlay_Unicode) {
99  const char *contents =
100      "{\n"
101      "  'version': 0,\n"
102      "  'roots': [\n"
103      "    {\n"
104      "      'type': 'directory',\n"
105      "      'name': \"/path/\\u266B\",\n"
106      "      'contents': [\n"
107      "        {\n"
108      "          'type': 'file',\n"
109      "          'name': \"\\u2602.h\",\n"
110      "          'external-contents': \"/real/\\u2602.h\"\n"
111      "        }\n"
112      "      ]\n"
113      "    }\n"
114      "  ]\n"
115      "}\n";
116  TestVFO T(contents);
117  T.map("/path/♫/☂.h""/real/☂.h");
118}
119
120TEST(libclang, VirtualFileOverlay_InvalidArgs) {
121  TestVFO T(nullptr);
122  T.mapError("/path/./virtual/../foo.h""/real/foo.h",
123             CXError_InvalidArguments);
124}
125
126TEST(libclang, VirtualFileOverlay_RemapDirectories) {
127  const char *contents =
128      "{\n"
129      "  'version': 0,\n"
130      "  'roots': [\n"
131      "    {\n"
132      "      'type': 'directory',\n"
133      "      'name': \"/another/dir\",\n"
134      "      'contents': [\n"
135      "        {\n"
136      "          'type': 'file',\n"
137      "          'name': \"foo2.h\",\n"
138      "          'external-contents': \"/real/foo2.h\"\n"
139      "        }\n"
140      "      ]\n"
141      "    },\n"
142      "    {\n"
143      "      'type': 'directory',\n"
144      "      'name': \"/path/virtual/dir\",\n"
145      "      'contents': [\n"
146      "        {\n"
147      "          'type': 'file',\n"
148      "          'name': \"foo1.h\",\n"
149      "          'external-contents': \"/real/foo1.h\"\n"
150      "        },\n"
151      "        {\n"
152      "          'type': 'file',\n"
153      "          'name': \"foo3.h\",\n"
154      "          'external-contents': \"/real/foo3.h\"\n"
155      "        },\n"
156      "        {\n"
157      "          'type': 'directory',\n"
158      "          'name': \"in/subdir\",\n"
159      "          'contents': [\n"
160      "            {\n"
161      "              'type': 'file',\n"
162      "              'name': \"foo4.h\",\n"
163      "              'external-contents': \"/real/foo4.h\"\n"
164      "            }\n"
165      "          ]\n"
166      "        }\n"
167      "      ]\n"
168      "    }\n"
169      "  ]\n"
170      "}\n";
171  TestVFO T(contents);
172  T.map("/path/virtual/dir/foo1.h""/real/foo1.h");
173  T.map("/another/dir/foo2.h""/real/foo2.h");
174  T.map("/path/virtual/dir/foo3.h""/real/foo3.h");
175  T.map("/path/virtual/dir/in/subdir/foo4.h""/real/foo4.h");
176}
177
178TEST(libclang, VirtualFileOverlay_CaseInsensitive) {
179  const char *contents =
180      "{\n"
181      "  'version': 0,\n"
182      "  'case-sensitive': 'false',\n"
183      "  'roots': [\n"
184      "    {\n"
185      "      'type': 'directory',\n"
186      "      'name': \"/path/virtual\",\n"
187      "      'contents': [\n"
188      "        {\n"
189      "          'type': 'file',\n"
190      "          'name': \"foo.h\",\n"
191      "          'external-contents': \"/real/foo.h\"\n"
192      "        }\n"
193      "      ]\n"
194      "    }\n"
195      "  ]\n"
196      "}\n";
197  TestVFO T(contents);
198  T.map("/path/virtual/foo.h""/real/foo.h");
199  clang_VirtualFileOverlay_setCaseSensitivity(T.VFOfalse);
200}
201
202TEST(libclang, VirtualFileOverlay_SharedPrefix) {
203  const char *contents =
204      "{\n"
205      "  'version': 0,\n"
206      "  'roots': [\n"
207      "    {\n"
208      "      'type': 'directory',\n"
209      "      'name': \"/path/foo\",\n"
210      "      'contents': [\n"
211      "        {\n"
212      "          'type': 'file',\n"
213      "          'name': \"bar\",\n"
214      "          'external-contents': \"/real/bar\"\n"
215      "        },\n"
216      "        {\n"
217      "          'type': 'file',\n"
218      "          'name': \"bar.h\",\n"
219      "          'external-contents': \"/real/bar.h\"\n"
220      "        }\n"
221      "      ]\n"
222      "    },\n"
223      "    {\n"
224      "      'type': 'directory',\n"
225      "      'name': \"/path/foobar\",\n"
226      "      'contents': [\n"
227      "        {\n"
228      "          'type': 'file',\n"
229      "          'name': \"baz.h\",\n"
230      "          'external-contents': \"/real/baz.h\"\n"
231      "        }\n"
232      "      ]\n"
233      "    },\n"
234      "    {\n"
235      "      'type': 'directory',\n"
236      "      'name': \"/path\",\n"
237      "      'contents': [\n"
238      "        {\n"
239      "          'type': 'file',\n"
240      "          'name': \"foobarbaz.h\",\n"
241      "          'external-contents': \"/real/foobarbaz.h\"\n"
242      "        }\n"
243      "      ]\n"
244      "    }\n"
245      "  ]\n"
246      "}\n";
247  TestVFO T(contents);
248  T.map("/path/foo/bar.h""/real/bar.h");
249  T.map("/path/foo/bar""/real/bar");
250  T.map("/path/foobar/baz.h""/real/baz.h");
251  T.map("/path/foobarbaz.h""/real/foobarbaz.h");
252}
253
254TEST(libclang, VirtualFileOverlay_AdjacentDirectory) {
255  const char *contents =
256      "{\n"
257      "  'version': 0,\n"
258      "  'roots': [\n"
259      "    {\n"
260      "      'type': 'directory',\n"
261      "      'name': \"/path/dir1\",\n"
262      "      'contents': [\n"
263      "        {\n"
264      "          'type': 'file',\n"
265      "          'name': \"foo.h\",\n"
266      "          'external-contents': \"/real/foo.h\"\n"
267      "        },\n"
268      "        {\n"
269      "          'type': 'directory',\n"
270      "          'name': \"subdir\",\n"
271      "          'contents': [\n"
272      "            {\n"
273      "              'type': 'file',\n"
274      "              'name': \"bar.h\",\n"
275      "              'external-contents': \"/real/bar.h\"\n"
276      "            }\n"
277      "          ]\n"
278      "        }\n"
279      "      ]\n"
280      "    },\n"
281      "    {\n"
282      "      'type': 'directory',\n"
283      "      'name': \"/path/dir2\",\n"
284      "      'contents': [\n"
285      "        {\n"
286      "          'type': 'file',\n"
287      "          'name': \"baz.h\",\n"
288      "          'external-contents': \"/real/baz.h\"\n"
289      "        }\n"
290      "      ]\n"
291      "    }\n"
292      "  ]\n"
293      "}\n";
294  TestVFO T(contents);
295  T.map("/path/dir1/foo.h""/real/foo.h");
296  T.map("/path/dir1/subdir/bar.h""/real/bar.h");
297  T.map("/path/dir2/baz.h""/real/baz.h");
298}
299
300TEST(libclang, VirtualFileOverlay_TopLevel) {
301  const char *contents =
302      "{\n"
303      "  'version': 0,\n"
304      "  'roots': [\n"
305      "    {\n"
306      "      'type': 'directory',\n"
307      "      'name': \"/\",\n"
308      "      'contents': [\n"
309      "        {\n"
310      "          'type': 'file',\n"
311      "          'name': \"foo.h\",\n"
312      "          'external-contents': \"/real/foo.h\"\n"
313      "        }\n"
314      "      ]\n"
315      "    }\n"
316      "  ]\n"
317      "}\n";
318  TestVFO T(contents);
319  T.map("/foo.h""/real/foo.h");
320}
321
322TEST(libclang, VirtualFileOverlay_Empty) {
323  const char *contents =
324      "{\n"
325      "  'version': 0,\n"
326      "  'roots': [\n"
327      "  ]\n"
328      "}\n";
329  TestVFO T(contents);
330}
331
332TEST(libclang, ModuleMapDescriptor) {
333  const char *Contents =
334    "framework module TestFrame {\n"
335    "  umbrella header \"TestFrame.h\"\n"
336    "\n"
337    "  export *\n"
338    "  module * { export * }\n"
339    "}\n";
340
341  CXModuleMapDescriptor MMD = clang_ModuleMapDescriptor_create(0);
342
343  clang_ModuleMapDescriptor_setFrameworkModuleName(MMD"TestFrame");
344  clang_ModuleMapDescriptor_setUmbrellaHeader(MMD"TestFrame.h");
345
346  char *BufPtr;
347  unsigned BufSize;
348  clang_ModuleMapDescriptor_writeToBuffer(MMD0, &BufPtr, &BufSize);
349  std::string BufStr(BufPtrBufSize);
350  EXPECT_STREQ(ContentsBufStr.c_str());
351  clang_free(BufPtr);
352  clang_ModuleMapDescriptor_dispose(MMD);
353}
354
355class LibclangParseTest : public ::testing::Test {
356  std::set<std::stringFiles;
357  typedef std::unique_ptr<std::stringfixed_addr_string;
358  std::map<fixed_addr_stringfixed_addr_stringUnsavedFileContents;
359public:
360  std::string TestDir;
361  CXIndex Index;
362  CXTranslationUnit ClangTU;
363  unsigned TUFlags;
364  std::vector<CXUnsavedFile> UnsavedFiles;
365
366  void SetUp() override {
367    llvm::SmallString<256> Dir;
368    ASSERT_FALSE(llvm::sys::fs::createUniqueDirectory("libclang-test", Dir));
369    TestDir = Dir.str();
370    TUFlags = CXTranslationUnit_DetailedPreprocessingRecord |
371      clang_defaultEditingTranslationUnitOptions();
372    Index = clang_createIndex(00);
373    ClangTU = nullptr;
374  }
375  void TearDown() override {
376    clang_disposeTranslationUnit(ClangTU);
377    clang_disposeIndex(Index);
378    for (const std::string &Path : Files)
379      llvm::sys::fs::remove(Path);
380    llvm::sys::fs::remove(TestDir);
381  }
382  void WriteFile(std::string &Filenameconst std::string &Contents) {
383    if (!llvm::sys::path::is_absolute(Filename)) {
384      llvm::SmallString<256> Path(TestDir);
385      llvm::sys::path::append(Path, Filename);
386      Filename = Path.str();
387      Files.insert(Filename);
388    }
389    llvm::sys::fs::create_directories(llvm::sys::path::parent_path(Filename));
390    std::ofstream OS(Filename);
391    OS << Contents;
392    assert(OS.good());
393  }
394  void MapUnsavedFile(std::string Filenameconst std::string &Contents) {
395    if (!llvm::sys::path::is_absolute(Filename)) {
396      llvm::SmallString<256> Path(TestDir);
397      llvm::sys::path::append(Path, Filename);
398      Filename = Path.str();
399    }
400    auto it = UnsavedFileContents.insert(std::make_pair(
401        fixed_addr_string(new std::string(Filename)),
402        fixed_addr_string(new std::string(Contents))));
403    UnsavedFiles.push_back({
404        it.first->first->c_str(),   // filename
405        it.first->second->c_str(),  // contents
406        it.first->second->size()    // length
407    });
408  }
409  template<typename F>
410  void Traverse(const F &TraversalFunctor) {
411    CXCursor TuCursor = clang_getTranslationUnitCursor(ClangTU);
412    std::reference_wrapper<const F> FunctorRef = std::cref(TraversalFunctor);
413    clang_visitChildren(TuCursor,
414        &TraverseStateless<std::reference_wrapper<const F>>,
415        &FunctorRef);
416  }
417private:
418  template<typename TState>
419  static CXChildVisitResult TraverseStateless(CXCursor cxCXCursor parent,
420      CXClientData data) {
421    TState *State = static_cast<TState*>(data);
422    return State->get()(cxparent);
423  }
424};
425
426TEST_F(LibclangParseTest, AllSkippedRanges) {
427  std::string Header = "header.h"Main = "main.cpp";
428  WriteFile(Header,
429    "#ifdef MANGOS\n"
430    "printf(\"mmm\");\n"
431    "#endif");
432  WriteFile(Main,
433    "#include \"header.h\"\n"
434    "#ifdef KIWIS\n"
435    "printf(\"mmm!!\");\n"
436    "#endif");
437
438  ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr0,
439                                       nullptr0, TUFlags);
440
441  CXSourceRangeList *Ranges = clang_getAllSkippedRanges(ClangTU);
442  EXPECT_EQ(2URanges->count);
443  
444  CXSourceLocation cxl;
445  unsigned line;
446  cxl = clang_getRangeStart(Ranges->ranges[0]);
447  clang_getSpellingLocation(cxlnullptr, &linenullptrnullptr);
448  EXPECT_EQ(1Uline);
449  cxl = clang_getRangeEnd(Ranges->ranges[0]);
450  clang_getSpellingLocation(cxlnullptr, &linenullptrnullptr);
451  EXPECT_EQ(3Uline);
452
453  cxl = clang_getRangeStart(Ranges->ranges[1]);
454  clang_getSpellingLocation(cxlnullptr, &linenullptrnullptr);
455  EXPECT_EQ(2Uline);
456  cxl = clang_getRangeEnd(Ranges->ranges[1]);
457  clang_getSpellingLocation(cxlnullptr, &linenullptrnullptr);
458  EXPECT_EQ(4Uline);
459
460  clang_disposeSourceRangeList(Ranges);
461}
462
463TEST_F(LibclangParseTest, EvaluateChildExpression) {
464  std::string Main = "main.m";
465  WriteFile(Main"#define kFOO @\"foo\"\n"
466                  "void foobar(void) {\n"
467                  " {kFOO;}\n"
468                  "}\n");
469  ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr0nullptr,
470                                       0, TUFlags);
471
472  CXCursor C = clang_getTranslationUnitCursor(ClangTU);
473  clang_visitChildren(
474      C,
475      [](CXCursor cursorCXCursor parent,
476         CXClientData client_data) -> CXChildVisitResult {
477        if (clang_getCursorKind(cursor) == CXCursor_FunctionDecl) {
478          int numberedStmt = 0;
479          clang_visitChildren(
480              cursor,
481              [](CXCursor cursorCXCursor parent,
482                 CXClientData client_data) -> CXChildVisitResult {
483                int &numberedStmt = *((int *)client_data);
484                if (clang_getCursorKind(cursor) == CXCursor_CompoundStmt) {
485                  if (numberedStmt) {
486                    CXEvalResult RE = clang_Cursor_Evaluate(cursor);
487                    EXPECT_NE(REnullptr);
488                    EXPECT_EQ(clang_EvalResult_getKind(RE),
489                              CXEval_ObjCStrLiteral);
490                    clang_EvalResult_dispose(RE);
491                    return CXChildVisit_Break;
492                  }
493                  numberedStmt++;
494                }
495                return CXChildVisit_Recurse;
496              },
497              &numberedStmt);
498          EXPECT_EQ(numberedStmt1);
499        }
500        return CXChildVisit_Continue;
501      },
502      nullptr);
503}
504
505class LibclangReparseTest : public LibclangParseTest {
506public:
507  void DisplayDiagnostics() {
508    unsigned NumDiagnostics = clang_getNumDiagnostics(ClangTU);
509    for (unsigned i = 0i < NumDiagnostics; ++i) {
510      auto Diag = clang_getDiagnostic(ClangTUi);
511      LLVM_DEBUG(llvm::dbgs()
512                 << clang_getCString(clang_formatDiagnostic(
513                        Diag, clang_defaultDiagnosticDisplayOptions()))
514                 << "\n");
515      clang_disposeDiagnostic(Diag);
516    }
517  }
518  bool ReparseTU(unsigned num_unsaved_filesCXUnsavedFileunsaved_files) {
519    if (clang_reparseTranslationUnit(ClangTUnum_unsaved_filesunsaved_files,
520                                     clang_defaultReparseOptions(ClangTU))) {
521      LLVM_DEBUG(llvm::dbgs() << "Reparse failed\n");
522      return false;
523    }
524    DisplayDiagnostics();
525    return true;
526  }
527};
528
529TEST_F(LibclangReparseTest, FileName) {
530  std::string CppName = "main.cpp";
531  WriteFile(CppName"int main() {}");
532  ClangTU = clang_parseTranslationUnit(Index, CppName.c_str(), nullptr0,
533                                       nullptr0, TUFlags);
534  CXFile cxf = clang_getFile(ClangTU, CppName.c_str());
535
536  CXString cxname = clang_getFileName(cxf);
537  ASSERT_STREQ(clang_getCString(cxname), CppName.c_str());
538  clang_disposeString(cxname);
539
540  cxname = clang_File_tryGetRealPathName(cxf);
541  ASSERT_TRUE(llvm::StringRef(clang_getCString(cxname)).endswith("main.cpp"));
542  clang_disposeString(cxname);
543}
544
545TEST_F(LibclangReparseTest, Reparse) {
546  const char *HeaderTop = "#ifndef H\n#define H\nstruct Foo { int bar;";
547  const char *HeaderBottom = "\n};\n#endif\n";
548  const char *CppFile = "#include \"HeaderFile.h\"\nint main() {"
549                         " Foo foo; foo.bar = 7; foo.baz = 8; }\n";
550  std::string HeaderName = "HeaderFile.h";
551  std::string CppName = "CppFile.cpp";
552  WriteFile(CppNameCppFile);
553  WriteFile(HeaderNamestd::string(HeaderTop) + HeaderBottom);
554
555  ClangTU = clang_parseTranslationUnit(Index, CppName.c_str(), nullptr0,
556                                       nullptr0, TUFlags);
557  EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU));
558  DisplayDiagnostics();
559
560  // Immedaitely reparse.
561  ASSERT_TRUE(ReparseTU(0nullptr /* No unsaved files. */));
562  EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU));
563
564  std::string NewHeaderContents =
565      std::string(HeaderTop) + "int baz;" + HeaderBottom;
566  WriteFile(HeaderNameNewHeaderContents);
567
568  // Reparse after fix.
569  ASSERT_TRUE(ReparseTU(0nullptr /* No unsaved files. */));
570  EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU));
571}
572
573TEST_F(LibclangReparseTest, ReparseWithModule) {
574  const char *HeaderTop = "#ifndef H\n#define H\nstruct Foo { int bar;";
575  const char *HeaderBottom = "\n};\n#endif\n";
576  const char *MFile = "#include \"HeaderFile.h\"\nint main() {"
577                         " struct Foo foo; foo.bar = 7; foo.baz = 8; }\n";
578  const char *ModFile = "module A { header \"HeaderFile.h\" }\n";
579  std::string HeaderName = "HeaderFile.h";
580  std::string MName = "MFile.m";
581  std::string ModName = "module.modulemap";
582  WriteFile(MNameMFile);
583  WriteFile(HeaderNamestd::string(HeaderTop) + HeaderBottom);
584  WriteFile(ModNameModFile);
585
586  std::string ModulesCache = std::string("-fmodules-cache-path=") + TestDir;
587  const char *Args[] = { "-fmodules", ModulesCache.c_str(),
588                         "-I", TestDir.c_str() };
589  int NumArgs = sizeof(Args) / sizeof(Args[0]);
590  ClangTU = clang_parseTranslationUnit(Index, MName.c_str(), Args, NumArgs,
591                                       nullptr0, TUFlags);
592  EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU));
593  DisplayDiagnostics();
594
595  // Immedaitely reparse.
596  ASSERT_TRUE(ReparseTU(0nullptr /* No unsaved files. */));
597  EXPECT_EQ(1U, clang_getNumDiagnostics(ClangTU));
598
599  std::string NewHeaderContents =
600      std::string(HeaderTop) + "int baz;" + HeaderBottom;
601  WriteFile(HeaderNameNewHeaderContents);
602
603  // Reparse after fix.
604  ASSERT_TRUE(ReparseTU(0nullptr /* No unsaved files. */));
605  EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU));
606}
607
608TEST_F(LibclangReparseTest, clang_parseTranslationUnit2FullArgv) {
609  // Provide a fake GCC 99.9.9 standard library that always overrides any local
610  // GCC installation.
611  std::string EmptyFiles[] = {"lib/gcc/arm-linux-gnueabi/99.9.9/crtbegin.o",
612                              "include/arm-linux-gnueabi/.keep",
613                              "include/c++/99.9.9/vector"};
614
615  for (auto &Name : EmptyFiles)
616    WriteFile(Name"\n");
617
618  std::string Filename = "test.cc";
619  WriteFile(Filename"#include <vector>\n");
620
621  std::string Clang = "bin/clang";
622  WriteFile(Clang"");
623
624  const char *Argv[] = {Clang.c_str(), "-target""arm-linux-gnueabi",
625                        "-stdlib=libstdc++""--gcc-toolchain="};
626
627  EXPECT_EQ(CXError_Success,
628            clang_parseTranslationUnit2FullArgv(Index, Filename.c_str(), Argv,
629                                                sizeof(Argv) / sizeof(Argv[0]),
630                                                nullptr0, TUFlags, &ClangTU));
631  EXPECT_EQ(0U, clang_getNumDiagnostics(ClangTU));
632  DisplayDiagnostics();
633}
634
635class LibclangPrintingPolicyTest : public LibclangParseTest {
636public:
637  CXPrintingPolicy Policy = nullptr;
638
639  void SetUp() override {
640    LibclangParseTest::SetUp();
641    std::string File = "file.cpp";
642    WriteFile(File"int i;\n");
643    ClangTU = clang_parseTranslationUnit(IndexFile.c_str(), nullptr0,
644                                         nullptr0TUFlags);
645    CXCursor TUCursor = clang_getTranslationUnitCursor(ClangTU);
646    Policy = clang_getCursorPrintingPolicy(TUCursor);
647  }
648  void TearDown() override {
649    clang_PrintingPolicy_dispose(Policy);
650    LibclangParseTest::TearDown();
651  }
652};
653
654TEST_F(LibclangPrintingPolicyTest, SetAndGetProperties) {
655  for (unsigned Value = 0Value < 2; ++Value) {
656    for (int I = 0I < CXPrintingPolicy_LastProperty; ++I) {
657      auto Property = static_cast<enum CXPrintingPolicyProperty>(I);
658
659      clang_PrintingPolicy_setProperty(Policy, Property, Value);
660      EXPECT_EQ(Value, clang_PrintingPolicy_getProperty(Policy, Property));
661    }
662  }
663}
664
665TEST_F(LibclangReparseTest, PreprocessorSkippedRanges) {
666  std::string Header = "header.h"Main = "main.cpp";
667  WriteFile(Header,
668    "#ifdef MANGOS\n"
669    "printf(\"mmm\");\n"
670    "#endif");
671  WriteFile(Main,
672    "#include \"header.h\"\n"
673    "#ifdef GUAVA\n"
674    "#endif\n"
675    "#ifdef KIWIS\n"
676    "printf(\"mmm!!\");\n"
677    "#endif");
678
679  for (int i = 0i != 3; ++i) {
680    unsigned flags = TUFlags | CXTranslationUnit_PrecompiledPreamble;
681    if (i == 2)
682      flags |= CXTranslationUnit_CreatePreambleOnFirstParse;
683
684    if (i != 0)
685       clang_disposeTranslationUnit(ClangTU);  // dispose from previous iter
686
687    // parse once
688    ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr0,
689                                         nullptr0, flags);
690    if (i != 0) {
691      // reparse
692      ASSERT_TRUE(ReparseTU(0nullptr /* No unsaved files. */));
693    }
694
695    // Check all ranges are there
696    CXSourceRangeList *Ranges = clang_getAllSkippedRanges(ClangTU);
697    EXPECT_EQ(3URanges->count);
698
699    CXSourceLocation cxl;
700    unsigned line;
701    cxl = clang_getRangeStart(Ranges->ranges[0]);
702    clang_getSpellingLocation(cxlnullptr, &linenullptrnullptr);
703    EXPECT_EQ(1Uline);
704    cxl = clang_getRangeEnd(Ranges->ranges[0]);
705    clang_getSpellingLocation(cxlnullptr, &linenullptrnullptr);
706    EXPECT_EQ(3Uline);
707
708    cxl = clang_getRangeStart(Ranges->ranges[1]);
709    clang_getSpellingLocation(cxlnullptr, &linenullptrnullptr);
710    EXPECT_EQ(2Uline);
711    cxl = clang_getRangeEnd(Ranges->ranges[1]);
712    clang_getSpellingLocation(cxlnullptr, &linenullptrnullptr);
713    EXPECT_EQ(3Uline);
714
715    cxl = clang_getRangeStart(Ranges->ranges[2]);
716    clang_getSpellingLocation(cxlnullptr, &linenullptrnullptr);
717    EXPECT_EQ(4Uline);
718    cxl = clang_getRangeEnd(Ranges->ranges[2]);
719    clang_getSpellingLocation(cxlnullptr, &linenullptrnullptr);
720    EXPECT_EQ(6Uline);
721
722    clang_disposeSourceRangeList(Ranges);
723
724    // Check obtaining ranges by each file works
725    CXFile cxf = clang_getFile(ClangTU, Header.c_str());
726    Ranges = clang_getSkippedRanges(ClangTU, cxf);
727    EXPECT_EQ(1URanges->count);
728    cxl = clang_getRangeStart(Ranges->ranges[0]);
729    clang_getSpellingLocation(cxlnullptr, &linenullptrnullptr);
730    EXPECT_EQ(1Uline);
731    clang_disposeSourceRangeList(Ranges);
732
733    cxf = clang_getFile(ClangTU, Main.c_str());
734    Ranges = clang_getSkippedRanges(ClangTU, cxf);
735    EXPECT_EQ(2URanges->count);
736    cxl = clang_getRangeStart(Ranges->ranges[0]);
737    clang_getSpellingLocation(cxlnullptr, &linenullptrnullptr);
738    EXPECT_EQ(2Uline);
739    cxl = clang_getRangeStart(Ranges->ranges[1]);
740    clang_getSpellingLocation(cxlnullptr, &linenullptrnullptr);
741    EXPECT_EQ(4Uline);
742    clang_disposeSourceRangeList(Ranges);
743  }
744}
745
746class LibclangSerializationTest : public LibclangParseTest {
747public:
748  bool SaveAndLoadTU(const std::string &Filename) {
749    unsigned options = clang_defaultSaveOptions(ClangTU);
750    if (clang_saveTranslationUnit(ClangTUFilename.c_str(), options) !=
751        CXSaveError_None) {
752      LLVM_DEBUG(llvm::dbgs() << "Saving failed\n");
753      return false;
754    }
755
756    clang_disposeTranslationUnit(ClangTU);
757
758    ClangTU = clang_createTranslationUnit(IndexFilename.c_str());
759
760    if (!ClangTU) {
761      LLVM_DEBUG(llvm::dbgs() << "Loading failed\n");
762      return false;
763    }
764
765    return true;
766  }
767};
768
769TEST_F(LibclangSerializationTest, TokenKindsAreCorrectAfterLoading) {
770  // Ensure that "class" is recognized as a keyword token after serializing
771  // and reloading the AST, as it is not a keyword for the default LangOptions.
772  std::string HeaderName = "test.h";
773  WriteFile(HeaderName"enum class Something {};");
774
775  const char *Argv[] = {"-xc++-header""-std=c++11"};
776
777  ClangTU = clang_parseTranslationUnit(Index, HeaderName.c_str(), Argv,
778                                       sizeof(Argv) / sizeof(Argv[0]), nullptr,
779                                       0, TUFlags);
780
781  auto CheckTokenKinds = [=]() {
782    CXSourceRange Range =
783        clang_getCursorExtent(clang_getTranslationUnitCursor(ClangTU));
784
785    CXToken *Tokens;
786    unsigned int NumTokens;
787    clang_tokenize(ClangTU, Range, &Tokens, &NumTokens);
788
789    ASSERT_EQ(6uNumTokens);
790    EXPECT_EQ(CXToken_Keywordclang_getTokenKind(Tokens[0]));
791    EXPECT_EQ(CXToken_Keywordclang_getTokenKind(Tokens[1]));
792    EXPECT_EQ(CXToken_Identifierclang_getTokenKind(Tokens[2]));
793    EXPECT_EQ(CXToken_Punctuationclang_getTokenKind(Tokens[3]));
794    EXPECT_EQ(CXToken_Punctuationclang_getTokenKind(Tokens[4]));
795    EXPECT_EQ(CXToken_Punctuationclang_getTokenKind(Tokens[5]));
796
797    clang_disposeTokens(ClangTU, Tokens, NumTokens);
798  };
799
800  CheckTokenKinds();
801
802  std::string ASTName = "test.ast";
803  WriteFile(ASTName"");
804
805  ASSERT_TRUE(SaveAndLoadTU(ASTName));
806
807  CheckTokenKinds();
808}
809