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