blob: 34893b71f08f45f97b444424ff57f53c4f65e44e [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
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000030using namespace clang;
31
32namespace {
33
34// Stub out module loading.
35class VoidModuleLoader : public ModuleLoader {
John Thompson2d94bbb2014-04-23 19:04:32 +000036 ModuleLoadResult loadModule(SourceLocation ImportLoc,
37 ModuleIdPath Path,
38 Module::NameVisibilityKind Visibility,
39 bool IsInclusionDirective) override {
Douglas Gregor8c058932012-11-30 00:01:57 +000040 return ModuleLoadResult();
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000041 }
NAKAMURA Takumie73d2a92013-01-12 02:16:29 +000042
John Thompson2d94bbb2014-04-23 19:04:32 +000043 void makeModuleVisible(Module *Mod,
44 Module::NameVisibilityKind Visibility,
Richard Smitha7e2cc62015-05-01 01:53:09 +000045 SourceLocation ImportLoc) override { }
John Thompson2255f2c2014-04-23 12:57:01 +000046
John Thompson2d94bbb2014-04-23 19:04:32 +000047 GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
Craig Topper416fa342014-06-08 08:38:12 +000048 { return nullptr; }
John Thompson2d94bbb2014-04-23 19:04:32 +000049 bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
Hans Wennborg4afe5042015-07-22 20:46:26 +000050 { return 0; }
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000051};
52
53// Stub to collect data from InclusionDirective callbacks.
54class InclusionDirectiveCallbacks : public PPCallbacks {
55public:
Alexander Kornienko34eb2072015-04-11 02:00:23 +000056 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 {
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000061 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
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +000083// Stub to collect data from PragmaOpenCLExtension callbacks.
84class PragmaOpenCLExtensionCallbacks : public PPCallbacks {
85public:
86 typedef struct {
Alexey Samsonov05747f32013-10-14 07:13:59 +000087 SmallString<16> Name;
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +000088 unsigned State;
89 } CallbackParameters;
90
Hans Wennborg4afe5042015-07-22 20:46:26 +000091 PragmaOpenCLExtensionCallbacks() : Name("Not called."), State(99) {}
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +000092
Alexander Kornienko34eb2072015-04-11 02:00:23 +000093 void PragmaOpenCLExtension(clang::SourceLocation NameLoc,
94 const clang::IdentifierInfo *Name,
95 clang::SourceLocation StateLoc,
96 unsigned State) override {
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +000097 this->NameLoc = NameLoc;
Alexey Samsonov05747f32013-10-14 07:13:59 +000098 this->Name = Name->getName();
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +000099 this->StateLoc = StateLoc;
100 this->State = State;
Hans Wennborg4afe5042015-07-22 20:46:26 +0000101 }
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000102
103 SourceLocation NameLoc;
Alexey Samsonov05747f32013-10-14 07:13:59 +0000104 SmallString<16> Name;
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000105 SourceLocation StateLoc;
106 unsigned State;
107};
108
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000109// PPCallbacks test fixture.
110class PPCallbacksTest : public ::testing::Test {
111protected:
112 PPCallbacksTest()
Benjamin Kramer46d311d2015-10-08 14:20:14 +0000113 : InMemoryFileSystem(new vfs::InMemoryFileSystem),
114 FileMgr(FileSystemOptions(), InMemoryFileSystem),
115 DiagID(new DiagnosticIDs()), DiagOpts(new DiagnosticOptions()),
Alp Toker80758082014-07-06 05:26:44 +0000116 Diags(DiagID, DiagOpts.get(), new IgnoringDiagConsumer()),
117 SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions()) {
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000118 TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
Alp Toker80758082014-07-06 05:26:44 +0000119 Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000120 }
121
Benjamin Kramer46d311d2015-10-08 14:20:14 +0000122 IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem;
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000123 FileManager FileMgr;
124 IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
125 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
126 DiagnosticsEngine Diags;
127 SourceManager SourceMgr;
128 LangOptions LangOpts;
Alp Toker80758082014-07-06 05:26:44 +0000129 std::shared_ptr<TargetOptions> TargetOpts;
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000130 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.
Benjamin Kramer46d311d2015-10-08 14:20:14 +0000137 InMemoryFileSystem->addFile(HeaderPath, 0,
138 llvm::MemoryBuffer::getMemBuffer("\n"));
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000139
140 // Add header's parent path to search path.
Alexey Samsonovd1127d22014-10-15 22:00:40 +0000141 StringRef SearchPath = llvm::sys::path::parent_path(HeaderPath);
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000142 const DirectoryEntry *DE = FileMgr.getDirectory(SearchPath);
Daniel Dunbarae4feb62013-01-25 01:50:28 +0000143 DirectoryLookup DL(DE, SrcMgr::C_User, false);
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000144 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) {
Alexey Samsonovd1127d22014-10-15 22:00:40 +0000159 std::unique_ptr<llvm::MemoryBuffer> Buf =
160 llvm::MemoryBuffer::getMemBuffer(SourceText);
David Blaikie50a5f972014-08-29 07:59:55 +0000161 SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000162
163 VoidModuleLoader ModLoader;
164
165 IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts = new HeaderSearchOptions();
Manuel Klimek1f76c4e2013-10-24 07:51:24 +0000166 HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts,
Alp Tokerf994cef2014-07-05 03:08:06 +0000167 Target.get());
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000168 AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
169
David Blaikiee3041682017-01-05 19:11:36 +0000170 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
171 SourceMgr, HeaderInfo, ModLoader,
Craig Topper416fa342014-06-08 08:38:12 +0000172 /*IILookup =*/nullptr,
Alp Toker96637802014-05-02 03:43:38 +0000173 /*OwnsHeaderSearch =*/false);
Alp Toker1ae02f62014-05-02 03:43:30 +0000174 PP.Initialize(*Target);
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000175 InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks;
Craig Topperb8a70532014-09-10 04:53:53 +0000176 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000177
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 }
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000191
192 PragmaOpenCLExtensionCallbacks::CallbackParameters
193 PragmaOpenCLExtensionCall(const char* SourceText) {
194 LangOptions OpenCLLangOpts;
195 OpenCLLangOpts.OpenCL = 1;
196
Alexey Samsonovd1127d22014-10-15 22:00:40 +0000197 std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
198 llvm::MemoryBuffer::getMemBuffer(SourceText, "test.cl");
David Blaikie50a5f972014-08-29 07:59:55 +0000199 SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000200
201 VoidModuleLoader ModLoader;
Manuel Klimek1f76c4e2013-10-24 07:51:24 +0000202 HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags,
Alp Tokerf994cef2014-07-05 03:08:06 +0000203 OpenCLLangOpts, Target.get());
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000204
David Blaikiee3041682017-01-05 19:11:36 +0000205 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags,
206 OpenCLLangOpts, SourceMgr, HeaderInfo, ModLoader,
207 /*IILookup =*/nullptr,
Alp Toker1ae02f62014-05-02 03:43:30 +0000208 /*OwnsHeaderSearch =*/false);
209 PP.Initialize(*Target);
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000210
211 // parser actually sets correct pragma handlers for preprocessor
212 // according to LangOptions, so we init Parser to register opencl
213 // pragma handlers
Alp Toker08043432014-05-03 03:46:04 +0000214 ASTContext Context(OpenCLLangOpts, SourceMgr,
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000215 PP.getIdentifierTable(), PP.getSelectorTable(),
Alp Toker08043432014-05-03 03:46:04 +0000216 PP.getBuiltinInfo());
217 Context.InitBuiltinTypes(*Target);
218
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000219 ASTConsumer Consumer;
220 Sema S(PP, Context, Consumer);
221 Parser P(PP, S, false);
222 PragmaOpenCLExtensionCallbacks* Callbacks = new PragmaOpenCLExtensionCallbacks;
Craig Topperb8a70532014-09-10 04:53:53 +0000223 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000224
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
Alexander Kornienkoab9db512015-06-22 23:07:51 +0000352} // anonoymous namespace