]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - unittests/Lex/PPCallbacksTest.cpp
Vendor import of clang trunk r256633:
[FreeBSD/FreeBSD.git] / unittests / Lex / PPCallbacksTest.cpp
1 //===- unittests/Lex/PPCallbacksTest.cpp - PPCallbacks tests ------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===--------------------------------------------------------------===//
9
10 #include "clang/Lex/Preprocessor.h"
11 #include "clang/AST/ASTConsumer.h"
12 #include "clang/AST/ASTContext.h"
13 #include "clang/Basic/Diagnostic.h"
14 #include "clang/Basic/DiagnosticOptions.h"
15 #include "clang/Basic/FileManager.h"
16 #include "clang/Basic/LangOptions.h"
17 #include "clang/Basic/SourceManager.h"
18 #include "clang/Basic/TargetInfo.h"
19 #include "clang/Basic/TargetOptions.h"
20 #include "clang/Lex/HeaderSearch.h"
21 #include "clang/Lex/HeaderSearchOptions.h"
22 #include "clang/Lex/ModuleLoader.h"
23 #include "clang/Lex/PreprocessorOptions.h"
24 #include "clang/Parse/Parser.h"
25 #include "clang/Sema/Sema.h"
26 #include "llvm/ADT/SmallString.h"
27 #include "llvm/Support/Path.h"
28 #include "gtest/gtest.h"
29
30 using namespace clang;
31
32 namespace {
33
34 // Stub out module loading.
35 class VoidModuleLoader : public ModuleLoader {
36   ModuleLoadResult loadModule(SourceLocation ImportLoc, 
37                               ModuleIdPath Path,
38                               Module::NameVisibilityKind Visibility,
39                               bool IsInclusionDirective) override {
40     return ModuleLoadResult();
41   }
42
43   void makeModuleVisible(Module *Mod,
44                          Module::NameVisibilityKind Visibility,
45                          SourceLocation ImportLoc) override { }
46
47   GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
48     { return nullptr; }
49   bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
50     { return 0; }
51 };
52
53 // Stub to collect data from InclusionDirective callbacks.
54 class InclusionDirectiveCallbacks : public PPCallbacks {
55 public:
56   void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
57                           StringRef FileName, bool IsAngled,
58                           CharSourceRange FilenameRange, const FileEntry *File,
59                           StringRef SearchPath, StringRef RelativePath,
60                           const Module *Imported) override {
61       this->HashLoc = HashLoc;
62       this->IncludeTok = IncludeTok;
63       this->FileName = FileName.str();
64       this->IsAngled = IsAngled;
65       this->FilenameRange = FilenameRange;
66       this->File = File;
67       this->SearchPath = SearchPath.str();
68       this->RelativePath = RelativePath.str();
69       this->Imported = Imported;
70   }
71
72   SourceLocation HashLoc;
73   Token IncludeTok;
74   SmallString<16> FileName;
75   bool IsAngled;
76   CharSourceRange FilenameRange;
77   const FileEntry* File;
78   SmallString<16> SearchPath;
79   SmallString<16> RelativePath;
80   const Module* Imported;
81 };
82
83 // Stub to collect data from PragmaOpenCLExtension callbacks.
84 class PragmaOpenCLExtensionCallbacks : public PPCallbacks {
85 public:
86   typedef struct {
87     SmallString<16> Name;
88     unsigned State;
89   } CallbackParameters;
90
91   PragmaOpenCLExtensionCallbacks() : Name("Not called."), State(99) {}
92
93   void PragmaOpenCLExtension(clang::SourceLocation NameLoc,
94                              const clang::IdentifierInfo *Name,
95                              clang::SourceLocation StateLoc,
96                              unsigned State) override {
97       this->NameLoc = NameLoc;
98       this->Name = Name->getName();
99       this->StateLoc = StateLoc;
100       this->State = State;
101   }
102
103   SourceLocation NameLoc;
104   SmallString<16> Name;
105   SourceLocation StateLoc;
106   unsigned State;
107 };
108
109 // PPCallbacks test fixture.
110 class PPCallbacksTest : public ::testing::Test {
111 protected:
112   PPCallbacksTest()
113       : InMemoryFileSystem(new vfs::InMemoryFileSystem),
114         FileMgr(FileSystemOptions(), InMemoryFileSystem),
115         DiagID(new DiagnosticIDs()), DiagOpts(new DiagnosticOptions()),
116         Diags(DiagID, DiagOpts.get(), new IgnoringDiagConsumer()),
117         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions()) {
118     TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
119     Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
120   }
121
122   IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem;
123   FileManager FileMgr;
124   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
125   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
126   DiagnosticsEngine Diags;
127   SourceManager SourceMgr;
128   LangOptions LangOpts;
129   std::shared_ptr<TargetOptions> TargetOpts;
130   IntrusiveRefCntPtr<TargetInfo> Target;
131
132   // Register a header path as a known file and add its location
133   // to search path.
134   void AddFakeHeader(HeaderSearch& HeaderInfo, const char* HeaderPath, 
135     bool IsSystemHeader) {
136       // Tell FileMgr about header.
137       InMemoryFileSystem->addFile(HeaderPath, 0,
138                                   llvm::MemoryBuffer::getMemBuffer("\n"));
139
140       // Add header's parent path to search path.
141       StringRef SearchPath = llvm::sys::path::parent_path(HeaderPath);
142       const DirectoryEntry *DE = FileMgr.getDirectory(SearchPath);
143       DirectoryLookup DL(DE, SrcMgr::C_User, false);
144       HeaderInfo.AddSearchPath(DL, IsSystemHeader);
145   }
146
147   // Get the raw source string of the range.
148   StringRef GetSourceString(CharSourceRange Range) {
149     const char* B = SourceMgr.getCharacterData(Range.getBegin());
150     const char* E = SourceMgr.getCharacterData(Range.getEnd());
151
152     return StringRef(B, E - B);
153   }
154
155   // Run lexer over SourceText and collect FilenameRange from
156   // the InclusionDirective callback.
157   CharSourceRange InclusionDirectiveFilenameRange(const char* SourceText, 
158       const char* HeaderPath, bool SystemHeader) {
159     std::unique_ptr<llvm::MemoryBuffer> Buf =
160         llvm::MemoryBuffer::getMemBuffer(SourceText);
161     SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
162
163     VoidModuleLoader ModLoader;
164
165     IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts = new HeaderSearchOptions();
166     HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts,
167                             Target.get());
168     AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
169
170     IntrusiveRefCntPtr<PreprocessorOptions> PPOpts = new PreprocessorOptions();
171     Preprocessor PP(PPOpts, Diags, LangOpts, SourceMgr, HeaderInfo, ModLoader,
172                     /*IILookup =*/nullptr,
173                     /*OwnsHeaderSearch =*/false);
174     PP.Initialize(*Target);
175     InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks;
176     PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
177
178     // Lex source text.
179     PP.EnterMainSourceFile();
180
181     while (true) {
182       Token Tok;
183       PP.Lex(Tok);
184       if (Tok.is(tok::eof))
185         break;
186     }
187
188     // Callbacks have been executed at this point -- return filename range.
189     return Callbacks->FilenameRange;
190   }
191
192   PragmaOpenCLExtensionCallbacks::CallbackParameters 
193   PragmaOpenCLExtensionCall(const char* SourceText) {
194     LangOptions OpenCLLangOpts;
195     OpenCLLangOpts.OpenCL = 1;
196
197     std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
198         llvm::MemoryBuffer::getMemBuffer(SourceText, "test.cl");
199     SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));
200
201     VoidModuleLoader ModLoader;
202     HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, 
203                             OpenCLLangOpts, Target.get());
204
205     Preprocessor PP(new PreprocessorOptions(), Diags, OpenCLLangOpts, SourceMgr,
206                     HeaderInfo, ModLoader, /*IILookup =*/nullptr,
207                     /*OwnsHeaderSearch =*/false);
208     PP.Initialize(*Target);
209
210     // parser actually sets correct pragma handlers for preprocessor
211     // according to LangOptions, so we init Parser to register opencl
212     // pragma handlers
213     ASTContext Context(OpenCLLangOpts, SourceMgr,
214                        PP.getIdentifierTable(), PP.getSelectorTable(), 
215                        PP.getBuiltinInfo());
216     Context.InitBuiltinTypes(*Target);
217
218     ASTConsumer Consumer;
219     Sema S(PP, Context, Consumer);
220     Parser P(PP, S, false);
221     PragmaOpenCLExtensionCallbacks* Callbacks = new PragmaOpenCLExtensionCallbacks;
222     PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
223
224     // Lex source text.
225     PP.EnterMainSourceFile();
226     while (true) {
227       Token Tok;
228       PP.Lex(Tok);
229       if (Tok.is(tok::eof))
230         break;
231     }
232
233     PragmaOpenCLExtensionCallbacks::CallbackParameters RetVal = {
234       Callbacks->Name,
235       Callbacks->State
236     };
237     return RetVal;    
238   }
239 };
240
241 TEST_F(PPCallbacksTest, QuotedFilename) {
242   const char* Source =
243     "#include \"quoted.h\"\n";
244
245   CharSourceRange Range =
246     InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
247
248   ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
249 }
250
251 TEST_F(PPCallbacksTest, AngledFilename) {
252   const char* Source =
253     "#include <angled.h>\n";
254
255   CharSourceRange Range =
256     InclusionDirectiveFilenameRange(Source, "/angled.h", true);
257
258   ASSERT_EQ("<angled.h>", GetSourceString(Range));
259 }
260
261 TEST_F(PPCallbacksTest, QuotedInMacro) {
262   const char* Source =
263     "#define MACRO_QUOTED \"quoted.h\"\n"
264     "#include MACRO_QUOTED\n";
265
266   CharSourceRange Range =
267     InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
268
269   ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
270 }
271
272 TEST_F(PPCallbacksTest, AngledInMacro) {
273   const char* Source =
274     "#define MACRO_ANGLED <angled.h>\n"
275     "#include MACRO_ANGLED\n";
276
277   CharSourceRange Range =
278     InclusionDirectiveFilenameRange(Source, "/angled.h", true);
279
280   ASSERT_EQ("<angled.h>", GetSourceString(Range));
281 }
282
283 TEST_F(PPCallbacksTest, StringizedMacroArgument) {
284   const char* Source =
285     "#define MACRO_STRINGIZED(x) #x\n"
286     "#include MACRO_STRINGIZED(quoted.h)\n";
287
288   CharSourceRange Range =
289     InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
290
291   ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
292 }
293
294 TEST_F(PPCallbacksTest, ConcatenatedMacroArgument) {
295   const char* Source =
296     "#define MACRO_ANGLED <angled.h>\n"
297     "#define MACRO_CONCAT(x, y) x ## _ ## y\n"
298     "#include MACRO_CONCAT(MACRO, ANGLED)\n";
299
300   CharSourceRange Range =
301     InclusionDirectiveFilenameRange(Source, "/angled.h", false);
302
303   ASSERT_EQ("<angled.h>", GetSourceString(Range));
304 }
305
306 TEST_F(PPCallbacksTest, TrigraphFilename) {
307   const char* Source =
308     "#include \"tri\?\?-graph.h\"\n";
309
310   CharSourceRange Range =
311     InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
312
313   ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
314 }
315
316 TEST_F(PPCallbacksTest, TrigraphInMacro) {
317   const char* Source =
318     "#define MACRO_TRIGRAPH \"tri\?\?-graph.h\"\n"
319     "#include MACRO_TRIGRAPH\n";
320
321   CharSourceRange Range =
322     InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
323
324   ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
325 }
326
327 TEST_F(PPCallbacksTest, OpenCLExtensionPragmaEnabled) {
328   const char* Source =
329     "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";
330
331   PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
332     PragmaOpenCLExtensionCall(Source);
333
334   ASSERT_EQ("cl_khr_fp64", Parameters.Name);
335   unsigned ExpectedState = 1;
336   ASSERT_EQ(ExpectedState, Parameters.State);
337 }
338
339 TEST_F(PPCallbacksTest, OpenCLExtensionPragmaDisabled) {
340   const char* Source =
341     "#pragma OPENCL EXTENSION cl_khr_fp16 : disable\n";
342
343   PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
344     PragmaOpenCLExtensionCall(Source);
345
346   ASSERT_EQ("cl_khr_fp16", Parameters.Name);
347   unsigned ExpectedState = 0;
348   ASSERT_EQ(ExpectedState, Parameters.State);
349 }
350
351 } // anonoymous namespace