blob: da641a7afb35b99f2489f36d172406168fb8c837 [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"
Stephen Hines6bcf27b2014-05-29 04:14:42 -070014#include "clang/Basic/DiagnosticOptions.h"
Argyrios Kyrtzidiscfa1caa2012-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 Kyrtzidiscfa1caa2012-11-01 17:52:58 +000023#include "clang/Lex/PreprocessorOptions.h"
Pekka Jaaskelainena0950e82013-10-12 09:29:48 +000024#include "clang/Parse/Parser.h"
25#include "clang/Sema/Sema.h"
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +000026#include "llvm/ADT/SmallString.h"
Rafael Espindola8229d222013-06-11 22:15:02 +000027#include "llvm/Support/Path.h"
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +000028#include "gtest/gtest.h"
29
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +000030using namespace clang;
31
32namespace {
33
34// Stub out module loading.
35class VoidModuleLoader : public ModuleLoader {
Stephen Hines6bcf27b2014-05-29 04:14:42 -070036 ModuleLoadResult loadModule(SourceLocation ImportLoc,
37 ModuleIdPath Path,
38 Module::NameVisibilityKind Visibility,
39 bool IsInclusionDirective) override {
Douglas Gregor7dff05b2012-11-30 00:01:57 +000040 return ModuleLoadResult();
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +000041 }
NAKAMURA Takumi1a4191d2013-01-12 02:16:29 +000042
Stephen Hines6bcf27b2014-05-29 04:14:42 -070043 void makeModuleVisible(Module *Mod,
44 Module::NameVisibilityKind Visibility,
45 SourceLocation ImportLoc,
46 bool Complain) override { }
47
48 GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
Stephen Hinesc568f1e2014-07-21 00:47:37 -070049 { return nullptr; }
Stephen Hines6bcf27b2014-05-29 04:14:42 -070050 bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
51 { return 0; };
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +000052};
53
54// Stub to collect data from InclusionDirective callbacks.
55class InclusionDirectiveCallbacks : public PPCallbacks {
56public:
Pirama Arumuga Nainar33337ca2015-05-06 11:48:57 -070057 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
58 StringRef FileName, bool IsAngled,
59 CharSourceRange FilenameRange, const FileEntry *File,
60 StringRef SearchPath, StringRef RelativePath,
61 const Module *Imported) override {
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +000062 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
Pirama Arumuga Nainar33337ca2015-05-06 11:48:57 -070094 void PragmaOpenCLExtension(clang::SourceLocation NameLoc,
95 const clang::IdentifierInfo *Name,
96 clang::SourceLocation StateLoc,
97 unsigned State) override {
Pekka Jaaskelainena0950e82013-10-12 09:29:48 +000098 this->NameLoc = NameLoc;
Alexey Samsonov74ecbd52013-10-14 07:13:59 +000099 this->Name = Name->getName();
Pekka Jaaskelainena0950e82013-10-12 09:29:48 +0000100 this->StateLoc = StateLoc;
101 this->State = State;
102 };
103
104 SourceLocation NameLoc;
Alexey Samsonov74ecbd52013-10-14 07:13:59 +0000105 SmallString<16> Name;
Pekka Jaaskelainena0950e82013-10-12 09:29:48 +0000106 SourceLocation StateLoc;
107 unsigned State;
108};
109
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000110// PPCallbacks test fixture.
111class PPCallbacksTest : public ::testing::Test {
112protected:
113 PPCallbacksTest()
Stephen Hinesc568f1e2014-07-21 00:47:37 -0700114 : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
115 DiagOpts(new DiagnosticOptions()),
116 Diags(DiagID, DiagOpts.get(), new IgnoringDiagConsumer()),
117 SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions()) {
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000118 TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
Stephen Hinesc568f1e2014-07-21 00:47:37 -0700119 Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000120 }
121
122 FileSystemOptions FileMgrOpts;
123 FileManager FileMgr;
124 IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
125 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
126 DiagnosticsEngine Diags;
127 SourceManager SourceMgr;
128 LangOptions LangOpts;
Stephen Hinesc568f1e2014-07-21 00:47:37 -0700129 std::shared_ptr<TargetOptions> TargetOpts;
Argyrios Kyrtzidiscfa1caa2012-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.
137 FileMgr.getVirtualFile(HeaderPath, 0, 0);
138
139 // Add header's parent path to search path.
Stephen Hines176edba2014-12-01 14:53:08 -0800140 StringRef SearchPath = llvm::sys::path::parent_path(HeaderPath);
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000141 const DirectoryEntry *DE = FileMgr.getDirectory(SearchPath);
Daniel Dunbar1ea6bc02013-01-25 01:50:28 +0000142 DirectoryLookup DL(DE, SrcMgr::C_User, false);
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000143 HeaderInfo.AddSearchPath(DL, IsSystemHeader);
144 }
145
146 // Get the raw source string of the range.
147 StringRef GetSourceString(CharSourceRange Range) {
148 const char* B = SourceMgr.getCharacterData(Range.getBegin());
149 const char* E = SourceMgr.getCharacterData(Range.getEnd());
150
151 return StringRef(B, E - B);
152 }
153
154 // Run lexer over SourceText and collect FilenameRange from
155 // the InclusionDirective callback.
156 CharSourceRange InclusionDirectiveFilenameRange(const char* SourceText,
157 const char* HeaderPath, bool SystemHeader) {
Stephen Hines176edba2014-12-01 14:53:08 -0800158 std::unique_ptr<llvm::MemoryBuffer> Buf =
159 llvm::MemoryBuffer::getMemBuffer(SourceText);
160 SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000161
162 VoidModuleLoader ModLoader;
163
164 IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts = new HeaderSearchOptions();
Manuel Klimekee0cd372013-10-24 07:51:24 +0000165 HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts,
Stephen Hinesc568f1e2014-07-21 00:47:37 -0700166 Target.get());
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000167 AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
168
169 IntrusiveRefCntPtr<PreprocessorOptions> PPOpts = new PreprocessorOptions();
Stephen Hines6bcf27b2014-05-29 04:14:42 -0700170 Preprocessor PP(PPOpts, Diags, LangOpts, SourceMgr, HeaderInfo, ModLoader,
Stephen Hinesc568f1e2014-07-21 00:47:37 -0700171 /*IILookup =*/nullptr,
Stephen Hines6bcf27b2014-05-29 04:14:42 -0700172 /*OwnsHeaderSearch =*/false);
173 PP.Initialize(*Target);
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000174 InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks;
Stephen Hines176edba2014-12-01 14:53:08 -0800175 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000176
177 // Lex source text.
178 PP.EnterMainSourceFile();
179
180 while (true) {
181 Token Tok;
182 PP.Lex(Tok);
183 if (Tok.is(tok::eof))
184 break;
185 }
186
187 // Callbacks have been executed at this point -- return filename range.
188 return Callbacks->FilenameRange;
189 }
Pekka Jaaskelainena0950e82013-10-12 09:29:48 +0000190
191 PragmaOpenCLExtensionCallbacks::CallbackParameters
192 PragmaOpenCLExtensionCall(const char* SourceText) {
193 LangOptions OpenCLLangOpts;
194 OpenCLLangOpts.OpenCL = 1;
195
Stephen Hines176edba2014-12-01 14:53:08 -0800196 std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
197 llvm::MemoryBuffer::getMemBuffer(SourceText, "test.cl");
198 SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));
Pekka Jaaskelainena0950e82013-10-12 09:29:48 +0000199
200 VoidModuleLoader ModLoader;
Manuel Klimekee0cd372013-10-24 07:51:24 +0000201 HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags,
Stephen Hinesc568f1e2014-07-21 00:47:37 -0700202 OpenCLLangOpts, Target.get());
Pekka Jaaskelainena0950e82013-10-12 09:29:48 +0000203
Stephen Hines6bcf27b2014-05-29 04:14:42 -0700204 Preprocessor PP(new PreprocessorOptions(), Diags, OpenCLLangOpts, SourceMgr,
Stephen Hinesc568f1e2014-07-21 00:47:37 -0700205 HeaderInfo, ModLoader, /*IILookup =*/nullptr,
Stephen Hines6bcf27b2014-05-29 04:14:42 -0700206 /*OwnsHeaderSearch =*/false);
207 PP.Initialize(*Target);
Pekka Jaaskelainena0950e82013-10-12 09:29:48 +0000208
209 // parser actually sets correct pragma handlers for preprocessor
210 // according to LangOptions, so we init Parser to register opencl
211 // pragma handlers
Stephen Hines6bcf27b2014-05-29 04:14:42 -0700212 ASTContext Context(OpenCLLangOpts, SourceMgr,
Pekka Jaaskelainena0950e82013-10-12 09:29:48 +0000213 PP.getIdentifierTable(), PP.getSelectorTable(),
Stephen Hines6bcf27b2014-05-29 04:14:42 -0700214 PP.getBuiltinInfo());
215 Context.InitBuiltinTypes(*Target);
216
Pekka Jaaskelainena0950e82013-10-12 09:29:48 +0000217 ASTConsumer Consumer;
218 Sema S(PP, Context, Consumer);
219 Parser P(PP, S, false);
220 PragmaOpenCLExtensionCallbacks* Callbacks = new PragmaOpenCLExtensionCallbacks;
Stephen Hines176edba2014-12-01 14:53:08 -0800221 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
Pekka Jaaskelainena0950e82013-10-12 09:29:48 +0000222
223 // Lex source text.
224 PP.EnterMainSourceFile();
225 while (true) {
226 Token Tok;
227 PP.Lex(Tok);
228 if (Tok.is(tok::eof))
229 break;
230 }
231
232 PragmaOpenCLExtensionCallbacks::CallbackParameters RetVal = {
Alexey Samsonov74ecbd52013-10-14 07:13:59 +0000233 Callbacks->Name,
Pekka Jaaskelainena0950e82013-10-12 09:29:48 +0000234 Callbacks->State
235 };
236 return RetVal;
237 }
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000238};
239
240TEST_F(PPCallbacksTest, QuotedFilename) {
241 const char* Source =
242 "#include \"quoted.h\"\n";
243
244 CharSourceRange Range =
245 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
246
247 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
248}
249
250TEST_F(PPCallbacksTest, AngledFilename) {
251 const char* Source =
252 "#include <angled.h>\n";
253
254 CharSourceRange Range =
255 InclusionDirectiveFilenameRange(Source, "/angled.h", true);
256
257 ASSERT_EQ("<angled.h>", GetSourceString(Range));
258}
259
260TEST_F(PPCallbacksTest, QuotedInMacro) {
261 const char* Source =
262 "#define MACRO_QUOTED \"quoted.h\"\n"
263 "#include MACRO_QUOTED\n";
264
265 CharSourceRange Range =
266 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
267
268 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
269}
270
271TEST_F(PPCallbacksTest, AngledInMacro) {
272 const char* Source =
273 "#define MACRO_ANGLED <angled.h>\n"
274 "#include MACRO_ANGLED\n";
275
276 CharSourceRange Range =
277 InclusionDirectiveFilenameRange(Source, "/angled.h", true);
278
279 ASSERT_EQ("<angled.h>", GetSourceString(Range));
280}
281
282TEST_F(PPCallbacksTest, StringizedMacroArgument) {
283 const char* Source =
284 "#define MACRO_STRINGIZED(x) #x\n"
285 "#include MACRO_STRINGIZED(quoted.h)\n";
286
287 CharSourceRange Range =
288 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
289
290 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
291}
292
293TEST_F(PPCallbacksTest, ConcatenatedMacroArgument) {
294 const char* Source =
295 "#define MACRO_ANGLED <angled.h>\n"
296 "#define MACRO_CONCAT(x, y) x ## _ ## y\n"
297 "#include MACRO_CONCAT(MACRO, ANGLED)\n";
298
299 CharSourceRange Range =
300 InclusionDirectiveFilenameRange(Source, "/angled.h", false);
301
302 ASSERT_EQ("<angled.h>", GetSourceString(Range));
303}
304
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000305TEST_F(PPCallbacksTest, TrigraphFilename) {
306 const char* Source =
Benjamin Kramer71640952012-11-03 20:58:26 +0000307 "#include \"tri\?\?-graph.h\"\n";
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000308
309 CharSourceRange Range =
310 InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
311
Benjamin Kramer71640952012-11-03 20:58:26 +0000312 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000313}
314
315TEST_F(PPCallbacksTest, TrigraphInMacro) {
316 const char* Source =
Benjamin Kramer71640952012-11-03 20:58:26 +0000317 "#define MACRO_TRIGRAPH \"tri\?\?-graph.h\"\n"
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000318 "#include MACRO_TRIGRAPH\n";
319
320 CharSourceRange Range =
321 InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
322
Benjamin Kramer71640952012-11-03 20:58:26 +0000323 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000324}
325
Pekka Jaaskelainena0950e82013-10-12 09:29:48 +0000326TEST_F(PPCallbacksTest, OpenCLExtensionPragmaEnabled) {
327 const char* Source =
328 "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";
329
330 PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
331 PragmaOpenCLExtensionCall(Source);
332
333 ASSERT_EQ("cl_khr_fp64", Parameters.Name);
334 unsigned ExpectedState = 1;
335 ASSERT_EQ(ExpectedState, Parameters.State);
336}
337
338TEST_F(PPCallbacksTest, OpenCLExtensionPragmaDisabled) {
339 const char* Source =
340 "#pragma OPENCL EXTENSION cl_khr_fp16 : disable\n";
341
342 PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
343 PragmaOpenCLExtensionCall(Source);
344
345 ASSERT_EQ("cl_khr_fp16", Parameters.Name);
346 unsigned ExpectedState = 0;
347 ASSERT_EQ(ExpectedState, Parameters.State);
348}
349
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000350} // anonoymous namespace