blob: cceebea6c183937cd2bea4aa7d56060d8dc93083 [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"
Benjamin Kramerf3ca26982014-05-10 16:31:55 +000014#include "clang/Basic/DiagnosticOptions.h"
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000015#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"
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000023#include "clang/Lex/PreprocessorOptions.h"
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +000024#include "clang/Parse/Parser.h"
25#include "clang/Sema/Sema.h"
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000026#include "llvm/ADT/SmallString.h"
Rafael Espindola552c1692013-06-11 22:15:02 +000027#include "llvm/Support/Path.h"
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000028#include "gtest/gtest.h"
29
30using namespace llvm;
31using namespace llvm::sys;
32using namespace clang;
33
34namespace {
35
36// Stub out module loading.
37class VoidModuleLoader : public ModuleLoader {
John Thompson2d94bbb2014-04-23 19:04:32 +000038 ModuleLoadResult loadModule(SourceLocation ImportLoc,
39 ModuleIdPath Path,
40 Module::NameVisibilityKind Visibility,
41 bool IsInclusionDirective) override {
Douglas Gregor8c058932012-11-30 00:01:57 +000042 return ModuleLoadResult();
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000043 }
NAKAMURA Takumie73d2a92013-01-12 02:16:29 +000044
John Thompson2d94bbb2014-04-23 19:04:32 +000045 void makeModuleVisible(Module *Mod,
46 Module::NameVisibilityKind Visibility,
47 SourceLocation ImportLoc,
48 bool Complain) override { }
John Thompson2255f2c2014-04-23 12:57:01 +000049
John Thompson2d94bbb2014-04-23 19:04:32 +000050 GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
John Thompson2255f2c2014-04-23 12:57:01 +000051 { return 0; }
John Thompson2d94bbb2014-04-23 19:04:32 +000052 bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
53 { return 0; };
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000054};
55
56// Stub to collect data from InclusionDirective callbacks.
57class InclusionDirectiveCallbacks : public PPCallbacks {
58public:
59 void InclusionDirective(SourceLocation HashLoc,
60 const Token &IncludeTok,
61 StringRef FileName,
62 bool IsAngled,
63 CharSourceRange FilenameRange,
64 const FileEntry *File,
65 StringRef SearchPath,
66 StringRef RelativePath,
67 const Module *Imported) {
68 this->HashLoc = HashLoc;
69 this->IncludeTok = IncludeTok;
70 this->FileName = FileName.str();
71 this->IsAngled = IsAngled;
72 this->FilenameRange = FilenameRange;
73 this->File = File;
74 this->SearchPath = SearchPath.str();
75 this->RelativePath = RelativePath.str();
76 this->Imported = Imported;
77 }
78
79 SourceLocation HashLoc;
80 Token IncludeTok;
81 SmallString<16> FileName;
82 bool IsAngled;
83 CharSourceRange FilenameRange;
84 const FileEntry* File;
85 SmallString<16> SearchPath;
86 SmallString<16> RelativePath;
87 const Module* Imported;
88};
89
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +000090// Stub to collect data from PragmaOpenCLExtension callbacks.
91class PragmaOpenCLExtensionCallbacks : public PPCallbacks {
92public:
93 typedef struct {
Alexey Samsonov05747f32013-10-14 07:13:59 +000094 SmallString<16> Name;
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +000095 unsigned State;
96 } CallbackParameters;
97
98 PragmaOpenCLExtensionCallbacks() : Name("Not called."), State(99) {};
99
100 void PragmaOpenCLExtension(
101 clang::SourceLocation NameLoc, const clang::IdentifierInfo *Name,
102 clang::SourceLocation StateLoc, unsigned State) {
103 this->NameLoc = NameLoc;
Alexey Samsonov05747f32013-10-14 07:13:59 +0000104 this->Name = Name->getName();
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000105 this->StateLoc = StateLoc;
106 this->State = State;
107 };
108
109 SourceLocation NameLoc;
Alexey Samsonov05747f32013-10-14 07:13:59 +0000110 SmallString<16> Name;
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000111 SourceLocation StateLoc;
112 unsigned State;
113};
114
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000115// PPCallbacks test fixture.
116class PPCallbacksTest : public ::testing::Test {
117protected:
118 PPCallbacksTest()
119 : FileMgr(FileMgrOpts),
120 DiagID(new DiagnosticIDs()),
121 DiagOpts(new DiagnosticOptions()),
122 Diags(DiagID, DiagOpts.getPtr(), new IgnoringDiagConsumer()),
123 SourceMgr(Diags, FileMgr) {
124 TargetOpts = new TargetOptions();
125 TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
NAKAMURA Takumife40a352012-11-16 04:40:11 +0000126 Target = TargetInfo::CreateTargetInfo(Diags, &*TargetOpts);
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000127 }
128
129 FileSystemOptions FileMgrOpts;
130 FileManager FileMgr;
131 IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
132 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
133 DiagnosticsEngine Diags;
134 SourceManager SourceMgr;
135 LangOptions LangOpts;
136 IntrusiveRefCntPtr<TargetOptions> TargetOpts;
137 IntrusiveRefCntPtr<TargetInfo> Target;
138
139 // Register a header path as a known file and add its location
140 // to search path.
141 void AddFakeHeader(HeaderSearch& HeaderInfo, const char* HeaderPath,
142 bool IsSystemHeader) {
143 // Tell FileMgr about header.
144 FileMgr.getVirtualFile(HeaderPath, 0, 0);
145
146 // Add header's parent path to search path.
147 StringRef SearchPath = path::parent_path(HeaderPath);
148 const DirectoryEntry *DE = FileMgr.getDirectory(SearchPath);
Daniel Dunbarae4feb62013-01-25 01:50:28 +0000149 DirectoryLookup DL(DE, SrcMgr::C_User, false);
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000150 HeaderInfo.AddSearchPath(DL, IsSystemHeader);
151 }
152
153 // Get the raw source string of the range.
154 StringRef GetSourceString(CharSourceRange Range) {
155 const char* B = SourceMgr.getCharacterData(Range.getBegin());
156 const char* E = SourceMgr.getCharacterData(Range.getEnd());
157
158 return StringRef(B, E - B);
159 }
160
161 // Run lexer over SourceText and collect FilenameRange from
162 // the InclusionDirective callback.
163 CharSourceRange InclusionDirectiveFilenameRange(const char* SourceText,
164 const char* HeaderPath, bool SystemHeader) {
165 MemoryBuffer *Buf = MemoryBuffer::getMemBuffer(SourceText);
Alp Tokerb671e342014-05-21 01:12:41 +0000166 SourceMgr.setMainFileID(SourceMgr.createFileID(Buf));
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000167
168 VoidModuleLoader ModLoader;
169
170 IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts = new HeaderSearchOptions();
Manuel Klimek1f76c4e2013-10-24 07:51:24 +0000171 HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts,
172 Target.getPtr());
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000173 AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
174
175 IntrusiveRefCntPtr<PreprocessorOptions> PPOpts = new PreprocessorOptions();
Alp Toker96637802014-05-02 03:43:38 +0000176 Preprocessor PP(PPOpts, Diags, LangOpts, SourceMgr, HeaderInfo, ModLoader,
177 /*IILookup =*/0,
178 /*OwnsHeaderSearch =*/false);
Alp Toker1ae02f62014-05-02 03:43:30 +0000179 PP.Initialize(*Target);
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000180 InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks;
181 PP.addPPCallbacks(Callbacks); // Takes ownership.
182
183 // Lex source text.
184 PP.EnterMainSourceFile();
185
186 while (true) {
187 Token Tok;
188 PP.Lex(Tok);
189 if (Tok.is(tok::eof))
190 break;
191 }
192
193 // Callbacks have been executed at this point -- return filename range.
194 return Callbacks->FilenameRange;
195 }
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000196
197 PragmaOpenCLExtensionCallbacks::CallbackParameters
198 PragmaOpenCLExtensionCall(const char* SourceText) {
199 LangOptions OpenCLLangOpts;
200 OpenCLLangOpts.OpenCL = 1;
201
202 MemoryBuffer* sourceBuf = MemoryBuffer::getMemBuffer(SourceText, "test.cl");
Alp Tokerb671e342014-05-21 01:12:41 +0000203 SourceMgr.setMainFileID(SourceMgr.createFileID(sourceBuf));
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000204
205 VoidModuleLoader ModLoader;
Manuel Klimek1f76c4e2013-10-24 07:51:24 +0000206 HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags,
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000207 OpenCLLangOpts, Target.getPtr());
208
Alp Toker96637802014-05-02 03:43:38 +0000209 Preprocessor PP(new PreprocessorOptions(), Diags, OpenCLLangOpts, SourceMgr,
210 HeaderInfo, ModLoader, /*IILookup =*/0,
Alp Toker1ae02f62014-05-02 03:43:30 +0000211 /*OwnsHeaderSearch =*/false);
212 PP.Initialize(*Target);
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000213
214 // parser actually sets correct pragma handlers for preprocessor
215 // according to LangOptions, so we init Parser to register opencl
216 // pragma handlers
Alp Toker08043432014-05-03 03:46:04 +0000217 ASTContext Context(OpenCLLangOpts, SourceMgr,
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000218 PP.getIdentifierTable(), PP.getSelectorTable(),
Alp Toker08043432014-05-03 03:46:04 +0000219 PP.getBuiltinInfo());
220 Context.InitBuiltinTypes(*Target);
221
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000222 ASTConsumer Consumer;
223 Sema S(PP, Context, Consumer);
224 Parser P(PP, S, false);
225 PragmaOpenCLExtensionCallbacks* Callbacks = new PragmaOpenCLExtensionCallbacks;
226 PP.addPPCallbacks(Callbacks); // Takes ownership.
227
228 // Lex source text.
229 PP.EnterMainSourceFile();
230 while (true) {
231 Token Tok;
232 PP.Lex(Tok);
233 if (Tok.is(tok::eof))
234 break;
235 }
236
237 PragmaOpenCLExtensionCallbacks::CallbackParameters RetVal = {
Alexey Samsonov05747f32013-10-14 07:13:59 +0000238 Callbacks->Name,
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000239 Callbacks->State
240 };
241 return RetVal;
242 }
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000243};
244
245TEST_F(PPCallbacksTest, QuotedFilename) {
246 const char* Source =
247 "#include \"quoted.h\"\n";
248
249 CharSourceRange Range =
250 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
251
252 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
253}
254
255TEST_F(PPCallbacksTest, AngledFilename) {
256 const char* Source =
257 "#include <angled.h>\n";
258
259 CharSourceRange Range =
260 InclusionDirectiveFilenameRange(Source, "/angled.h", true);
261
262 ASSERT_EQ("<angled.h>", GetSourceString(Range));
263}
264
265TEST_F(PPCallbacksTest, QuotedInMacro) {
266 const char* Source =
267 "#define MACRO_QUOTED \"quoted.h\"\n"
268 "#include MACRO_QUOTED\n";
269
270 CharSourceRange Range =
271 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
272
273 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
274}
275
276TEST_F(PPCallbacksTest, AngledInMacro) {
277 const char* Source =
278 "#define MACRO_ANGLED <angled.h>\n"
279 "#include MACRO_ANGLED\n";
280
281 CharSourceRange Range =
282 InclusionDirectiveFilenameRange(Source, "/angled.h", true);
283
284 ASSERT_EQ("<angled.h>", GetSourceString(Range));
285}
286
287TEST_F(PPCallbacksTest, StringizedMacroArgument) {
288 const char* Source =
289 "#define MACRO_STRINGIZED(x) #x\n"
290 "#include MACRO_STRINGIZED(quoted.h)\n";
291
292 CharSourceRange Range =
293 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
294
295 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
296}
297
298TEST_F(PPCallbacksTest, ConcatenatedMacroArgument) {
299 const char* Source =
300 "#define MACRO_ANGLED <angled.h>\n"
301 "#define MACRO_CONCAT(x, y) x ## _ ## y\n"
302 "#include MACRO_CONCAT(MACRO, ANGLED)\n";
303
304 CharSourceRange Range =
305 InclusionDirectiveFilenameRange(Source, "/angled.h", false);
306
307 ASSERT_EQ("<angled.h>", GetSourceString(Range));
308}
309
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000310TEST_F(PPCallbacksTest, TrigraphFilename) {
311 const char* Source =
Benjamin Kramerf9db1302012-11-03 20:58:26 +0000312 "#include \"tri\?\?-graph.h\"\n";
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000313
314 CharSourceRange Range =
315 InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
316
Benjamin Kramerf9db1302012-11-03 20:58:26 +0000317 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000318}
319
320TEST_F(PPCallbacksTest, TrigraphInMacro) {
321 const char* Source =
Benjamin Kramerf9db1302012-11-03 20:58:26 +0000322 "#define MACRO_TRIGRAPH \"tri\?\?-graph.h\"\n"
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000323 "#include MACRO_TRIGRAPH\n";
324
325 CharSourceRange Range =
326 InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
327
Benjamin Kramerf9db1302012-11-03 20:58:26 +0000328 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000329}
330
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000331TEST_F(PPCallbacksTest, OpenCLExtensionPragmaEnabled) {
332 const char* Source =
333 "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";
334
335 PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
336 PragmaOpenCLExtensionCall(Source);
337
338 ASSERT_EQ("cl_khr_fp64", Parameters.Name);
339 unsigned ExpectedState = 1;
340 ASSERT_EQ(ExpectedState, Parameters.State);
341}
342
343TEST_F(PPCallbacksTest, OpenCLExtensionPragmaDisabled) {
344 const char* Source =
345 "#pragma OPENCL EXTENSION cl_khr_fp16 : disable\n";
346
347 PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
348 PragmaOpenCLExtensionCall(Source);
349
350 ASSERT_EQ("cl_khr_fp16", Parameters.Name);
351 unsigned ExpectedState = 0;
352 ASSERT_EQ(ExpectedState, Parameters.State);
353}
354
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000355} // anonoymous namespace