blob: e3a4a76a774c7fa418a243c7ef8aaa4ed0b71e38 [file] [log] [blame]
Argyrios Kyrtzidiscfa1caa2012-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 Carruth1050e8b2012-12-04 09:45:34 +000010#include "clang/Lex/Preprocessor.h"
Stephen Hines651f13c2014-04-23 16:59:28 -070011#include "clang/AST/ASTConsumer.h"
12#include "clang/AST/ASTContext.h"
Argyrios Kyrtzidiscfa1caa2012-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 Kyrtzidiscfa1caa2012-11-01 17:52:58 +000022#include "clang/Lex/PreprocessorOptions.h"
Pekka Jaaskelainena0950e82013-10-12 09:29:48 +000023#include "clang/Parse/Parser.h"
24#include "clang/Sema/Sema.h"
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +000025#include "llvm/ADT/SmallString.h"
Rafael Espindola8229d222013-06-11 22:15:02 +000026#include "llvm/Support/Path.h"
Argyrios Kyrtzidiscfa1caa2012-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 {
Douglas Gregor7dff05b2012-11-30 00:01:57 +000037 virtual ModuleLoadResult loadModule(SourceLocation ImportLoc,
38 ModuleIdPath Path,
39 Module::NameVisibilityKind Visibility,
40 bool IsInclusionDirective) {
41 return ModuleLoadResult();
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +000042 }
NAKAMURA Takumi1a4191d2013-01-12 02:16:29 +000043
44 virtual void makeModuleVisible(Module *Mod,
Argyrios Kyrtzidis5ebcb202013-02-01 16:36:12 +000045 Module::NameVisibilityKind Visibility,
Douglas Gregor906d66a2013-03-20 21:10:35 +000046 SourceLocation ImportLoc,
47 bool Complain) { }
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +000048};
49
50// Stub to collect data from InclusionDirective callbacks.
51class InclusionDirectiveCallbacks : public PPCallbacks {
52public:
53 void InclusionDirective(SourceLocation HashLoc,
54 const Token &IncludeTok,
55 StringRef FileName,
56 bool IsAngled,
57 CharSourceRange FilenameRange,
58 const FileEntry *File,
59 StringRef SearchPath,
60 StringRef RelativePath,
61 const Module *Imported) {
62 this->HashLoc = HashLoc;
63 this->IncludeTok = IncludeTok;
64 this->FileName = FileName.str();
65 this->IsAngled = IsAngled;
66 this->FilenameRange = FilenameRange;
67 this->File = File;
68 this->SearchPath = SearchPath.str();
69 this->RelativePath = RelativePath.str();
70 this->Imported = Imported;
71 }
72
73 SourceLocation HashLoc;
74 Token IncludeTok;
75 SmallString<16> FileName;
76 bool IsAngled;
77 CharSourceRange FilenameRange;
78 const FileEntry* File;
79 SmallString<16> SearchPath;
80 SmallString<16> RelativePath;
81 const Module* Imported;
82};
83
Pekka Jaaskelainena0950e82013-10-12 09:29:48 +000084// Stub to collect data from PragmaOpenCLExtension callbacks.
85class PragmaOpenCLExtensionCallbacks : public PPCallbacks {
86public:
87 typedef struct {
Alexey Samsonov74ecbd52013-10-14 07:13:59 +000088 SmallString<16> Name;
Pekka Jaaskelainena0950e82013-10-12 09:29:48 +000089 unsigned State;
90 } CallbackParameters;
91
92 PragmaOpenCLExtensionCallbacks() : Name("Not called."), State(99) {};
93
94 void PragmaOpenCLExtension(
95 clang::SourceLocation NameLoc, const clang::IdentifierInfo *Name,
96 clang::SourceLocation StateLoc, unsigned State) {
97 this->NameLoc = NameLoc;
Alexey Samsonov74ecbd52013-10-14 07:13:59 +000098 this->Name = Name->getName();
Pekka Jaaskelainena0950e82013-10-12 09:29:48 +000099 this->StateLoc = StateLoc;
100 this->State = State;
101 };
102
103 SourceLocation NameLoc;
Alexey Samsonov74ecbd52013-10-14 07:13:59 +0000104 SmallString<16> Name;
Pekka Jaaskelainena0950e82013-10-12 09:29:48 +0000105 SourceLocation StateLoc;
106 unsigned State;
107};
108
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000109// PPCallbacks test fixture.
110class PPCallbacksTest : public ::testing::Test {
111protected:
112 PPCallbacksTest()
113 : FileMgr(FileMgrOpts),
114 DiagID(new DiagnosticIDs()),
115 DiagOpts(new DiagnosticOptions()),
116 Diags(DiagID, DiagOpts.getPtr(), new IgnoringDiagConsumer()),
117 SourceMgr(Diags, FileMgr) {
118 TargetOpts = new TargetOptions();
119 TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
NAKAMURA Takumi3a4c8cf2012-11-16 04:40:11 +0000120 Target = TargetInfo::CreateTargetInfo(Diags, &*TargetOpts);
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000121 }
122
123 FileSystemOptions FileMgrOpts;
124 FileManager FileMgr;
125 IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
126 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
127 DiagnosticsEngine Diags;
128 SourceManager SourceMgr;
129 LangOptions LangOpts;
130 IntrusiveRefCntPtr<TargetOptions> TargetOpts;
131 IntrusiveRefCntPtr<TargetInfo> Target;
132
133 // Register a header path as a known file and add its location
134 // to search path.
135 void AddFakeHeader(HeaderSearch& HeaderInfo, const char* HeaderPath,
136 bool IsSystemHeader) {
137 // Tell FileMgr about header.
138 FileMgr.getVirtualFile(HeaderPath, 0, 0);
139
140 // Add header's parent path to search path.
141 StringRef SearchPath = path::parent_path(HeaderPath);
142 const DirectoryEntry *DE = FileMgr.getDirectory(SearchPath);
Daniel Dunbar1ea6bc02013-01-25 01:50:28 +0000143 DirectoryLookup DL(DE, SrcMgr::C_User, false);
Argyrios Kyrtzidiscfa1caa2012-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) {
159 MemoryBuffer *Buf = MemoryBuffer::getMemBuffer(SourceText);
160 (void)SourceMgr.createMainFileIDForMemBuffer(Buf);
161
162 VoidModuleLoader ModLoader;
163
164 IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts = new HeaderSearchOptions();
Manuel Klimekee0cd372013-10-24 07:51:24 +0000165 HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts,
166 Target.getPtr());
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000167 AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
168
169 IntrusiveRefCntPtr<PreprocessorOptions> PPOpts = new PreprocessorOptions();
170 Preprocessor PP(PPOpts, Diags, LangOpts,
171 Target.getPtr(),
172 SourceMgr, HeaderInfo, ModLoader,
173 /*IILookup =*/ 0,
174 /*OwnsHeaderSearch =*/false,
175 /*DelayInitialization =*/ false);
176 InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks;
177 PP.addPPCallbacks(Callbacks); // Takes ownership.
178
179 // Lex source text.
180 PP.EnterMainSourceFile();
181
182 while (true) {
183 Token Tok;
184 PP.Lex(Tok);
185 if (Tok.is(tok::eof))
186 break;
187 }
188
189 // Callbacks have been executed at this point -- return filename range.
190 return Callbacks->FilenameRange;
191 }
Pekka Jaaskelainena0950e82013-10-12 09:29:48 +0000192
193 PragmaOpenCLExtensionCallbacks::CallbackParameters
194 PragmaOpenCLExtensionCall(const char* SourceText) {
195 LangOptions OpenCLLangOpts;
196 OpenCLLangOpts.OpenCL = 1;
197
198 MemoryBuffer* sourceBuf = MemoryBuffer::getMemBuffer(SourceText, "test.cl");
199 (void)SourceMgr.createMainFileIDForMemBuffer(sourceBuf);
200
201 VoidModuleLoader ModLoader;
Manuel Klimekee0cd372013-10-24 07:51:24 +0000202 HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags,
Pekka Jaaskelainena0950e82013-10-12 09:29:48 +0000203 OpenCLLangOpts, Target.getPtr());
204
205 Preprocessor PP(new PreprocessorOptions(), Diags, OpenCLLangOpts,
206 Target.getPtr(),
207 SourceMgr, HeaderInfo, ModLoader,
208 /*IILookup =*/ 0,
209 /*OwnsHeaderSearch =*/false,
210 /*DelayInitialization =*/ false);
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, Target.getPtr(),
216 PP.getIdentifierTable(), PP.getSelectorTable(),
217 PP.getBuiltinInfo(), 0);
218 ASTConsumer Consumer;
219 Sema S(PP, Context, Consumer);
220 Parser P(PP, S, false);
221 PragmaOpenCLExtensionCallbacks* Callbacks = new PragmaOpenCLExtensionCallbacks;
222 PP.addPPCallbacks(Callbacks); // Takes ownership.
223
224 // Lex source text.
225 PP.EnterMainSourceFile();
226 while (true) {
227 Token Tok;
228 PP.Lex(Tok);
229 if (Tok.is(tok::eof))
230 break;
231 }
232
233 PragmaOpenCLExtensionCallbacks::CallbackParameters RetVal = {
Alexey Samsonov74ecbd52013-10-14 07:13:59 +0000234 Callbacks->Name,
Pekka Jaaskelainena0950e82013-10-12 09:29:48 +0000235 Callbacks->State
236 };
237 return RetVal;
238 }
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000239};
240
241TEST_F(PPCallbacksTest, QuotedFilename) {
242 const char* Source =
243 "#include \"quoted.h\"\n";
244
245 CharSourceRange Range =
246 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
247
248 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
249}
250
251TEST_F(PPCallbacksTest, AngledFilename) {
252 const char* Source =
253 "#include <angled.h>\n";
254
255 CharSourceRange Range =
256 InclusionDirectiveFilenameRange(Source, "/angled.h", true);
257
258 ASSERT_EQ("<angled.h>", GetSourceString(Range));
259}
260
261TEST_F(PPCallbacksTest, QuotedInMacro) {
262 const char* Source =
263 "#define MACRO_QUOTED \"quoted.h\"\n"
264 "#include MACRO_QUOTED\n";
265
266 CharSourceRange Range =
267 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
268
269 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
270}
271
272TEST_F(PPCallbacksTest, AngledInMacro) {
273 const char* Source =
274 "#define MACRO_ANGLED <angled.h>\n"
275 "#include MACRO_ANGLED\n";
276
277 CharSourceRange Range =
278 InclusionDirectiveFilenameRange(Source, "/angled.h", true);
279
280 ASSERT_EQ("<angled.h>", GetSourceString(Range));
281}
282
283TEST_F(PPCallbacksTest, StringizedMacroArgument) {
284 const char* Source =
285 "#define MACRO_STRINGIZED(x) #x\n"
286 "#include MACRO_STRINGIZED(quoted.h)\n";
287
288 CharSourceRange Range =
289 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
290
291 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
292}
293
294TEST_F(PPCallbacksTest, ConcatenatedMacroArgument) {
295 const char* Source =
296 "#define MACRO_ANGLED <angled.h>\n"
297 "#define MACRO_CONCAT(x, y) x ## _ ## y\n"
298 "#include MACRO_CONCAT(MACRO, ANGLED)\n";
299
300 CharSourceRange Range =
301 InclusionDirectiveFilenameRange(Source, "/angled.h", false);
302
303 ASSERT_EQ("<angled.h>", GetSourceString(Range));
304}
305
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000306TEST_F(PPCallbacksTest, TrigraphFilename) {
307 const char* Source =
Benjamin Kramer71640952012-11-03 20:58:26 +0000308 "#include \"tri\?\?-graph.h\"\n";
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000309
310 CharSourceRange Range =
311 InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
312
Benjamin Kramer71640952012-11-03 20:58:26 +0000313 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000314}
315
316TEST_F(PPCallbacksTest, TrigraphInMacro) {
317 const char* Source =
Benjamin Kramer71640952012-11-03 20:58:26 +0000318 "#define MACRO_TRIGRAPH \"tri\?\?-graph.h\"\n"
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000319 "#include MACRO_TRIGRAPH\n";
320
321 CharSourceRange Range =
322 InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
323
Benjamin Kramer71640952012-11-03 20:58:26 +0000324 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000325}
326
Pekka Jaaskelainena0950e82013-10-12 09:29:48 +0000327TEST_F(PPCallbacksTest, OpenCLExtensionPragmaEnabled) {
328 const char* Source =
329 "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";
330
331 PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
332 PragmaOpenCLExtensionCall(Source);
333
334 ASSERT_EQ("cl_khr_fp64", Parameters.Name);
335 unsigned ExpectedState = 1;
336 ASSERT_EQ(ExpectedState, Parameters.State);
337}
338
339TEST_F(PPCallbacksTest, OpenCLExtensionPragmaDisabled) {
340 const char* Source =
341 "#pragma OPENCL EXTENSION cl_khr_fp16 : disable\n";
342
343 PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
344 PragmaOpenCLExtensionCall(Source);
345
346 ASSERT_EQ("cl_khr_fp16", Parameters.Name);
347 unsigned ExpectedState = 0;
348 ASSERT_EQ(ExpectedState, Parameters.State);
349}
350
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000351} // anonoymous namespace