blob: 043c3003ce9a1fc3c61cf85d1e3255e4d5bf2641 [file] [log] [blame]
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +00001//===- 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
Chandler Carruth320d9662012-12-04 09:45:34 +000010#include "clang/Lex/Preprocessor.h"
Chandler Carruth5553d0d2014-01-07 11:51:46 +000011#include "clang/AST/ASTConsumer.h"
12#include "clang/AST/ASTContext.h"
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000013#include "clang/Basic/Diagnostic.h"
14#include "clang/Basic/FileManager.h"
15#include "clang/Basic/LangOptions.h"
16#include "clang/Basic/SourceManager.h"
17#include "clang/Basic/TargetInfo.h"
18#include "clang/Basic/TargetOptions.h"
19#include "clang/Lex/HeaderSearch.h"
20#include "clang/Lex/HeaderSearchOptions.h"
21#include "clang/Lex/ModuleLoader.h"
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000022#include "clang/Lex/PreprocessorOptions.h"
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +000023#include "clang/Parse/Parser.h"
24#include "clang/Sema/Sema.h"
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000025#include "llvm/ADT/SmallString.h"
Rafael Espindola552c1692013-06-11 22:15:02 +000026#include "llvm/Support/Path.h"
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000027#include "gtest/gtest.h"
28
29using namespace llvm;
30using namespace llvm::sys;
31using namespace clang;
32
33namespace {
34
35// Stub out module loading.
36class VoidModuleLoader : public ModuleLoader {
John Thompson2d94bbb2014-04-23 19:04:32 +000037 ModuleLoadResult loadModule(SourceLocation ImportLoc,
38 ModuleIdPath Path,
39 Module::NameVisibilityKind Visibility,
40 bool IsInclusionDirective) override {
Douglas Gregor8c058932012-11-30 00:01:57 +000041 return ModuleLoadResult();
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000042 }
NAKAMURA Takumie73d2a92013-01-12 02:16:29 +000043
John Thompson2d94bbb2014-04-23 19:04:32 +000044 void makeModuleVisible(Module *Mod,
45 Module::NameVisibilityKind Visibility,
46 SourceLocation ImportLoc,
47 bool Complain) override { }
John Thompson2255f2c2014-04-23 12:57:01 +000048
John Thompson2d94bbb2014-04-23 19:04:32 +000049 GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
John Thompson2255f2c2014-04-23 12:57:01 +000050 { return 0; }
John Thompson2d94bbb2014-04-23 19:04:32 +000051 bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
52 { return 0; };
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000053};
54
55// Stub to collect data from InclusionDirective callbacks.
56class InclusionDirectiveCallbacks : public PPCallbacks {
57public:
58 void InclusionDirective(SourceLocation HashLoc,
59 const Token &IncludeTok,
60 StringRef FileName,
61 bool IsAngled,
62 CharSourceRange FilenameRange,
63 const FileEntry *File,
64 StringRef SearchPath,
65 StringRef RelativePath,
66 const Module *Imported) {
67 this->HashLoc = HashLoc;
68 this->IncludeTok = IncludeTok;
69 this->FileName = FileName.str();
70 this->IsAngled = IsAngled;
71 this->FilenameRange = FilenameRange;
72 this->File = File;
73 this->SearchPath = SearchPath.str();
74 this->RelativePath = RelativePath.str();
75 this->Imported = Imported;
76 }
77
78 SourceLocation HashLoc;
79 Token IncludeTok;
80 SmallString<16> FileName;
81 bool IsAngled;
82 CharSourceRange FilenameRange;
83 const FileEntry* File;
84 SmallString<16> SearchPath;
85 SmallString<16> RelativePath;
86 const Module* Imported;
87};
88
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +000089// Stub to collect data from PragmaOpenCLExtension callbacks.
90class PragmaOpenCLExtensionCallbacks : public PPCallbacks {
91public:
92 typedef struct {
Alexey Samsonov05747f32013-10-14 07:13:59 +000093 SmallString<16> Name;
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +000094 unsigned State;
95 } CallbackParameters;
96
97 PragmaOpenCLExtensionCallbacks() : Name("Not called."), State(99) {};
98
99 void PragmaOpenCLExtension(
100 clang::SourceLocation NameLoc, const clang::IdentifierInfo *Name,
101 clang::SourceLocation StateLoc, unsigned State) {
102 this->NameLoc = NameLoc;
Alexey Samsonov05747f32013-10-14 07:13:59 +0000103 this->Name = Name->getName();
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000104 this->StateLoc = StateLoc;
105 this->State = State;
106 };
107
108 SourceLocation NameLoc;
Alexey Samsonov05747f32013-10-14 07:13:59 +0000109 SmallString<16> Name;
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000110 SourceLocation StateLoc;
111 unsigned State;
112};
113
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000114// PPCallbacks test fixture.
115class PPCallbacksTest : public ::testing::Test {
116protected:
117 PPCallbacksTest()
118 : FileMgr(FileMgrOpts),
119 DiagID(new DiagnosticIDs()),
120 DiagOpts(new DiagnosticOptions()),
121 Diags(DiagID, DiagOpts.getPtr(), new IgnoringDiagConsumer()),
122 SourceMgr(Diags, FileMgr) {
123 TargetOpts = new TargetOptions();
124 TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
NAKAMURA Takumife40a352012-11-16 04:40:11 +0000125 Target = TargetInfo::CreateTargetInfo(Diags, &*TargetOpts);
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000126 }
127
128 FileSystemOptions FileMgrOpts;
129 FileManager FileMgr;
130 IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
131 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
132 DiagnosticsEngine Diags;
133 SourceManager SourceMgr;
134 LangOptions LangOpts;
135 IntrusiveRefCntPtr<TargetOptions> TargetOpts;
136 IntrusiveRefCntPtr<TargetInfo> Target;
137
138 // Register a header path as a known file and add its location
139 // to search path.
140 void AddFakeHeader(HeaderSearch& HeaderInfo, const char* HeaderPath,
141 bool IsSystemHeader) {
142 // Tell FileMgr about header.
143 FileMgr.getVirtualFile(HeaderPath, 0, 0);
144
145 // Add header's parent path to search path.
146 StringRef SearchPath = path::parent_path(HeaderPath);
147 const DirectoryEntry *DE = FileMgr.getDirectory(SearchPath);
Daniel Dunbarae4feb62013-01-25 01:50:28 +0000148 DirectoryLookup DL(DE, SrcMgr::C_User, false);
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000149 HeaderInfo.AddSearchPath(DL, IsSystemHeader);
150 }
151
152 // Get the raw source string of the range.
153 StringRef GetSourceString(CharSourceRange Range) {
154 const char* B = SourceMgr.getCharacterData(Range.getBegin());
155 const char* E = SourceMgr.getCharacterData(Range.getEnd());
156
157 return StringRef(B, E - B);
158 }
159
160 // Run lexer over SourceText and collect FilenameRange from
161 // the InclusionDirective callback.
162 CharSourceRange InclusionDirectiveFilenameRange(const char* SourceText,
163 const char* HeaderPath, bool SystemHeader) {
164 MemoryBuffer *Buf = MemoryBuffer::getMemBuffer(SourceText);
165 (void)SourceMgr.createMainFileIDForMemBuffer(Buf);
166
167 VoidModuleLoader ModLoader;
168
169 IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts = new HeaderSearchOptions();
Manuel Klimek1f76c4e2013-10-24 07:51:24 +0000170 HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts,
171 Target.getPtr());
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000172 AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
173
174 IntrusiveRefCntPtr<PreprocessorOptions> PPOpts = new PreprocessorOptions();
Alp Toker96637802014-05-02 03:43:38 +0000175 Preprocessor PP(PPOpts, Diags, LangOpts, SourceMgr, HeaderInfo, ModLoader,
176 /*IILookup =*/0,
177 /*OwnsHeaderSearch =*/false);
Alp Toker1ae02f62014-05-02 03:43:30 +0000178 PP.Initialize(*Target);
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000179 InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks;
180 PP.addPPCallbacks(Callbacks); // Takes ownership.
181
182 // Lex source text.
183 PP.EnterMainSourceFile();
184
185 while (true) {
186 Token Tok;
187 PP.Lex(Tok);
188 if (Tok.is(tok::eof))
189 break;
190 }
191
192 // Callbacks have been executed at this point -- return filename range.
193 return Callbacks->FilenameRange;
194 }
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000195
196 PragmaOpenCLExtensionCallbacks::CallbackParameters
197 PragmaOpenCLExtensionCall(const char* SourceText) {
198 LangOptions OpenCLLangOpts;
199 OpenCLLangOpts.OpenCL = 1;
200
201 MemoryBuffer* sourceBuf = MemoryBuffer::getMemBuffer(SourceText, "test.cl");
202 (void)SourceMgr.createMainFileIDForMemBuffer(sourceBuf);
203
204 VoidModuleLoader ModLoader;
Manuel Klimek1f76c4e2013-10-24 07:51:24 +0000205 HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags,
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000206 OpenCLLangOpts, Target.getPtr());
207
Alp Toker96637802014-05-02 03:43:38 +0000208 Preprocessor PP(new PreprocessorOptions(), Diags, OpenCLLangOpts, SourceMgr,
209 HeaderInfo, ModLoader, /*IILookup =*/0,
Alp Toker1ae02f62014-05-02 03:43:30 +0000210 /*OwnsHeaderSearch =*/false);
211 PP.Initialize(*Target);
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000212
213 // parser actually sets correct pragma handlers for preprocessor
214 // according to LangOptions, so we init Parser to register opencl
215 // pragma handlers
216 ASTContext Context(OpenCLLangOpts, SourceMgr, Target.getPtr(),
217 PP.getIdentifierTable(), PP.getSelectorTable(),
218 PP.getBuiltinInfo(), 0);
219 ASTConsumer Consumer;
220 Sema S(PP, Context, Consumer);
221 Parser P(PP, S, false);
222 PragmaOpenCLExtensionCallbacks* Callbacks = new PragmaOpenCLExtensionCallbacks;
223 PP.addPPCallbacks(Callbacks); // Takes ownership.
224
225 // Lex source text.
226 PP.EnterMainSourceFile();
227 while (true) {
228 Token Tok;
229 PP.Lex(Tok);
230 if (Tok.is(tok::eof))
231 break;
232 }
233
234 PragmaOpenCLExtensionCallbacks::CallbackParameters RetVal = {
Alexey Samsonov05747f32013-10-14 07:13:59 +0000235 Callbacks->Name,
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000236 Callbacks->State
237 };
238 return RetVal;
239 }
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000240};
241
242TEST_F(PPCallbacksTest, QuotedFilename) {
243 const char* Source =
244 "#include \"quoted.h\"\n";
245
246 CharSourceRange Range =
247 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
248
249 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
250}
251
252TEST_F(PPCallbacksTest, AngledFilename) {
253 const char* Source =
254 "#include <angled.h>\n";
255
256 CharSourceRange Range =
257 InclusionDirectiveFilenameRange(Source, "/angled.h", true);
258
259 ASSERT_EQ("<angled.h>", GetSourceString(Range));
260}
261
262TEST_F(PPCallbacksTest, QuotedInMacro) {
263 const char* Source =
264 "#define MACRO_QUOTED \"quoted.h\"\n"
265 "#include MACRO_QUOTED\n";
266
267 CharSourceRange Range =
268 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
269
270 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
271}
272
273TEST_F(PPCallbacksTest, AngledInMacro) {
274 const char* Source =
275 "#define MACRO_ANGLED <angled.h>\n"
276 "#include MACRO_ANGLED\n";
277
278 CharSourceRange Range =
279 InclusionDirectiveFilenameRange(Source, "/angled.h", true);
280
281 ASSERT_EQ("<angled.h>", GetSourceString(Range));
282}
283
284TEST_F(PPCallbacksTest, StringizedMacroArgument) {
285 const char* Source =
286 "#define MACRO_STRINGIZED(x) #x\n"
287 "#include MACRO_STRINGIZED(quoted.h)\n";
288
289 CharSourceRange Range =
290 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
291
292 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
293}
294
295TEST_F(PPCallbacksTest, ConcatenatedMacroArgument) {
296 const char* Source =
297 "#define MACRO_ANGLED <angled.h>\n"
298 "#define MACRO_CONCAT(x, y) x ## _ ## y\n"
299 "#include MACRO_CONCAT(MACRO, ANGLED)\n";
300
301 CharSourceRange Range =
302 InclusionDirectiveFilenameRange(Source, "/angled.h", false);
303
304 ASSERT_EQ("<angled.h>", GetSourceString(Range));
305}
306
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000307TEST_F(PPCallbacksTest, TrigraphFilename) {
308 const char* Source =
Benjamin Kramerf9db1302012-11-03 20:58:26 +0000309 "#include \"tri\?\?-graph.h\"\n";
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000310
311 CharSourceRange Range =
312 InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
313
Benjamin Kramerf9db1302012-11-03 20:58:26 +0000314 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000315}
316
317TEST_F(PPCallbacksTest, TrigraphInMacro) {
318 const char* Source =
Benjamin Kramerf9db1302012-11-03 20:58:26 +0000319 "#define MACRO_TRIGRAPH \"tri\?\?-graph.h\"\n"
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000320 "#include MACRO_TRIGRAPH\n";
321
322 CharSourceRange Range =
323 InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
324
Benjamin Kramerf9db1302012-11-03 20:58:26 +0000325 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000326}
327
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000328TEST_F(PPCallbacksTest, OpenCLExtensionPragmaEnabled) {
329 const char* Source =
330 "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";
331
332 PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
333 PragmaOpenCLExtensionCall(Source);
334
335 ASSERT_EQ("cl_khr_fp64", Parameters.Name);
336 unsigned ExpectedState = 1;
337 ASSERT_EQ(ExpectedState, Parameters.State);
338}
339
340TEST_F(PPCallbacksTest, OpenCLExtensionPragmaDisabled) {
341 const char* Source =
342 "#pragma OPENCL EXTENSION cl_khr_fp16 : disable\n";
343
344 PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
345 PragmaOpenCLExtensionCall(Source);
346
347 ASSERT_EQ("cl_khr_fp16", Parameters.Name);
348 unsigned ExpectedState = 0;
349 ASSERT_EQ(ExpectedState, Parameters.State);
350}
351
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000352} // anonoymous namespace