]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - unittests/Lex/PPCallbacksTest.cpp
Vendor import of clang trunk r238337:
[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       : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
114         DiagOpts(new DiagnosticOptions()),
115         Diags(DiagID, DiagOpts.get(), new IgnoringDiagConsumer()),
116         SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions()) {
117     TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
118     Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
119   }
120
121   FileSystemOptions FileMgrOpts;
122   FileManager FileMgr;
123   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
124   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
125   DiagnosticsEngine Diags;
126   SourceManager SourceMgr;
127   LangOptions LangOpts;
128   std::shared_ptr<TargetOptions> TargetOpts;
129   IntrusiveRefCntPtr<TargetInfo> Target;
130
131   // Register a header path as a known file and add its location
132   // to search path.
133   void AddFakeHeader(HeaderSearch& HeaderInfo, const char* HeaderPath, 
134     bool IsSystemHeader) {
135       // Tell FileMgr about header.
136       FileMgr.getVirtualFile(HeaderPath, 0, 0);
137
138       // Add header's parent path to search path.
139       StringRef SearchPath = llvm::sys::path::parent_path(HeaderPath);
140       const DirectoryEntry *DE = FileMgr.getDirectory(SearchPath);
141       DirectoryLookup DL(DE, SrcMgr::C_User, false);
142       HeaderInfo.AddSearchPath(DL, IsSystemHeader);
143   }
144
145   // Get the raw source string of the range.
146   StringRef GetSourceString(CharSourceRange Range) {
147     const char* B = SourceMgr.getCharacterData(Range.getBegin());
148     const char* E = SourceMgr.getCharacterData(Range.getEnd());
149
150     return StringRef(B, E - B);
151   }
152
153   // Run lexer over SourceText and collect FilenameRange from
154   // the InclusionDirective callback.
155   CharSourceRange InclusionDirectiveFilenameRange(const char* SourceText, 
156       const char* HeaderPath, bool SystemHeader) {
157     std::unique_ptr<llvm::MemoryBuffer> Buf =
158         llvm::MemoryBuffer::getMemBuffer(SourceText);
159     SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
160
161     VoidModuleLoader ModLoader;
162
163     IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts = new HeaderSearchOptions();
164     HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts,
165                             Target.get());
166     AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
167
168     IntrusiveRefCntPtr<PreprocessorOptions> PPOpts = new PreprocessorOptions();
169     Preprocessor PP(PPOpts, Diags, LangOpts, SourceMgr, HeaderInfo, ModLoader,
170                     /*IILookup =*/nullptr,
171                     /*OwnsHeaderSearch =*/false);
172     PP.Initialize(*Target);
173     InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks;
174     PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
175
176     // Lex source text.
177     PP.EnterMainSourceFile();
178
179     while (true) {
180       Token Tok;
181       PP.Lex(Tok);
182       if (Tok.is(tok::eof))
183         break;
184     }
185
186     // Callbacks have been executed at this point -- return filename range.
187     return Callbacks->FilenameRange;
188   }
189
190   PragmaOpenCLExtensionCallbacks::CallbackParameters 
191   PragmaOpenCLExtensionCall(const char* SourceText) {
192     LangOptions OpenCLLangOpts;
193     OpenCLLangOpts.OpenCL = 1;
194
195     std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
196         llvm::MemoryBuffer::getMemBuffer(SourceText, "test.cl");
197     SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));
198
199     VoidModuleLoader ModLoader;
200     HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, 
201                             OpenCLLangOpts, Target.get());
202
203     Preprocessor PP(new PreprocessorOptions(), Diags, OpenCLLangOpts, SourceMgr,
204                     HeaderInfo, ModLoader, /*IILookup =*/nullptr,
205                     /*OwnsHeaderSearch =*/false);
206     PP.Initialize(*Target);
207
208     // parser actually sets correct pragma handlers for preprocessor
209     // according to LangOptions, so we init Parser to register opencl
210     // pragma handlers
211     ASTContext Context(OpenCLLangOpts, SourceMgr,
212                        PP.getIdentifierTable(), PP.getSelectorTable(), 
213                        PP.getBuiltinInfo());
214     Context.InitBuiltinTypes(*Target);
215
216     ASTConsumer Consumer;
217     Sema S(PP, Context, Consumer);
218     Parser P(PP, S, false);
219     PragmaOpenCLExtensionCallbacks* Callbacks = new PragmaOpenCLExtensionCallbacks;
220     PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
221
222     // Lex source text.
223     PP.EnterMainSourceFile();
224     while (true) {
225       Token Tok;
226       PP.Lex(Tok);
227       if (Tok.is(tok::eof))
228         break;
229     }
230
231     PragmaOpenCLExtensionCallbacks::CallbackParameters RetVal = {
232       Callbacks->Name,
233       Callbacks->State
234     };
235     return RetVal;    
236   }
237 };
238
239 TEST_F(PPCallbacksTest, QuotedFilename) {
240   const char* Source =
241     "#include \"quoted.h\"\n";
242
243   CharSourceRange Range =
244     InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
245
246   ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
247 }
248
249 TEST_F(PPCallbacksTest, AngledFilename) {
250   const char* Source =
251     "#include <angled.h>\n";
252
253   CharSourceRange Range =
254     InclusionDirectiveFilenameRange(Source, "/angled.h", true);
255
256   ASSERT_EQ("<angled.h>", GetSourceString(Range));
257 }
258
259 TEST_F(PPCallbacksTest, QuotedInMacro) {
260   const char* Source =
261     "#define MACRO_QUOTED \"quoted.h\"\n"
262     "#include MACRO_QUOTED\n";
263
264   CharSourceRange Range =
265     InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
266
267   ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
268 }
269
270 TEST_F(PPCallbacksTest, AngledInMacro) {
271   const char* Source =
272     "#define MACRO_ANGLED <angled.h>\n"
273     "#include MACRO_ANGLED\n";
274
275   CharSourceRange Range =
276     InclusionDirectiveFilenameRange(Source, "/angled.h", true);
277
278   ASSERT_EQ("<angled.h>", GetSourceString(Range));
279 }
280
281 TEST_F(PPCallbacksTest, StringizedMacroArgument) {
282   const char* Source =
283     "#define MACRO_STRINGIZED(x) #x\n"
284     "#include MACRO_STRINGIZED(quoted.h)\n";
285
286   CharSourceRange Range =
287     InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
288
289   ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
290 }
291
292 TEST_F(PPCallbacksTest, ConcatenatedMacroArgument) {
293   const char* Source =
294     "#define MACRO_ANGLED <angled.h>\n"
295     "#define MACRO_CONCAT(x, y) x ## _ ## y\n"
296     "#include MACRO_CONCAT(MACRO, ANGLED)\n";
297
298   CharSourceRange Range =
299     InclusionDirectiveFilenameRange(Source, "/angled.h", false);
300
301   ASSERT_EQ("<angled.h>", GetSourceString(Range));
302 }
303
304 TEST_F(PPCallbacksTest, TrigraphFilename) {
305   const char* Source =
306     "#include \"tri\?\?-graph.h\"\n";
307
308   CharSourceRange Range =
309     InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
310
311   ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
312 }
313
314 TEST_F(PPCallbacksTest, TrigraphInMacro) {
315   const char* Source =
316     "#define MACRO_TRIGRAPH \"tri\?\?-graph.h\"\n"
317     "#include MACRO_TRIGRAPH\n";
318
319   CharSourceRange Range =
320     InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
321
322   ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
323 }
324
325 TEST_F(PPCallbacksTest, OpenCLExtensionPragmaEnabled) {
326   const char* Source =
327     "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";
328
329   PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
330     PragmaOpenCLExtensionCall(Source);
331
332   ASSERT_EQ("cl_khr_fp64", Parameters.Name);
333   unsigned ExpectedState = 1;
334   ASSERT_EQ(ExpectedState, Parameters.State);
335 }
336
337 TEST_F(PPCallbacksTest, OpenCLExtensionPragmaDisabled) {
338   const char* Source =
339     "#pragma OPENCL EXTENSION cl_khr_fp16 : disable\n";
340
341   PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
342     PragmaOpenCLExtensionCall(Source);
343
344   ASSERT_EQ("cl_khr_fp16", Parameters.Name);
345   unsigned ExpectedState = 0;
346   ASSERT_EQ(ExpectedState, Parameters.State);
347 }
348
349 } // anonoymous namespace