blob: 4f528712aef625af9c10c5fa639b3fc45adc6429 [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"
Duncan P. N. Exon Smith030d7d62017-03-20 17:58:26 +000017#include "clang/Basic/MemoryBufferCache.h"
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000018#include "clang/Basic/SourceManager.h"
19#include "clang/Basic/TargetInfo.h"
20#include "clang/Basic/TargetOptions.h"
21#include "clang/Lex/HeaderSearch.h"
22#include "clang/Lex/HeaderSearchOptions.h"
23#include "clang/Lex/ModuleLoader.h"
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000024#include "clang/Lex/PreprocessorOptions.h"
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +000025#include "clang/Parse/Parser.h"
26#include "clang/Sema/Sema.h"
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000027#include "llvm/ADT/SmallString.h"
Rafael Espindola552c1692013-06-11 22:15:02 +000028#include "llvm/Support/Path.h"
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000029#include "gtest/gtest.h"
30
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000031using namespace clang;
32
33namespace {
34
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000035// Stub to collect data from InclusionDirective callbacks.
36class InclusionDirectiveCallbacks : public PPCallbacks {
37public:
Alexander Kornienko34eb2072015-04-11 02:00:23 +000038 void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
39 StringRef FileName, bool IsAngled,
40 CharSourceRange FilenameRange, const FileEntry *File,
41 StringRef SearchPath, StringRef RelativePath,
Julie Hockett36d94ab2018-05-09 18:27:33 +000042 const Module *Imported,
43 SrcMgr::CharacteristicKind FileType) override {
44 this->HashLoc = HashLoc;
45 this->IncludeTok = IncludeTok;
46 this->FileName = FileName.str();
47 this->IsAngled = IsAngled;
48 this->FilenameRange = FilenameRange;
49 this->File = File;
50 this->SearchPath = SearchPath.str();
51 this->RelativePath = RelativePath.str();
52 this->Imported = Imported;
53 this->FileType = FileType;
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000054 }
55
56 SourceLocation HashLoc;
57 Token IncludeTok;
58 SmallString<16> FileName;
59 bool IsAngled;
60 CharSourceRange FilenameRange;
61 const FileEntry* File;
62 SmallString<16> SearchPath;
63 SmallString<16> RelativePath;
64 const Module* Imported;
Julie Hockett36d94ab2018-05-09 18:27:33 +000065 SrcMgr::CharacteristicKind FileType;
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000066};
67
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +000068// Stub to collect data from PragmaOpenCLExtension callbacks.
69class PragmaOpenCLExtensionCallbacks : public PPCallbacks {
70public:
71 typedef struct {
Alexey Samsonov05747f32013-10-14 07:13:59 +000072 SmallString<16> Name;
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +000073 unsigned State;
74 } CallbackParameters;
75
Hans Wennborg4afe5042015-07-22 20:46:26 +000076 PragmaOpenCLExtensionCallbacks() : Name("Not called."), State(99) {}
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +000077
Alexander Kornienko34eb2072015-04-11 02:00:23 +000078 void PragmaOpenCLExtension(clang::SourceLocation NameLoc,
79 const clang::IdentifierInfo *Name,
80 clang::SourceLocation StateLoc,
81 unsigned State) override {
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +000082 this->NameLoc = NameLoc;
Alexey Samsonov05747f32013-10-14 07:13:59 +000083 this->Name = Name->getName();
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +000084 this->StateLoc = StateLoc;
85 this->State = State;
Hans Wennborg4afe5042015-07-22 20:46:26 +000086 }
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +000087
88 SourceLocation NameLoc;
Alexey Samsonov05747f32013-10-14 07:13:59 +000089 SmallString<16> Name;
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +000090 SourceLocation StateLoc;
91 unsigned State;
92};
93
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +000094// PPCallbacks test fixture.
95class PPCallbacksTest : public ::testing::Test {
96protected:
97 PPCallbacksTest()
Benjamin Kramer46d311d2015-10-08 14:20:14 +000098 : InMemoryFileSystem(new vfs::InMemoryFileSystem),
99 FileMgr(FileSystemOptions(), InMemoryFileSystem),
100 DiagID(new DiagnosticIDs()), DiagOpts(new DiagnosticOptions()),
Alp Toker80758082014-07-06 05:26:44 +0000101 Diags(DiagID, DiagOpts.get(), new IgnoringDiagConsumer()),
102 SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions()) {
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000103 TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
Alp Toker80758082014-07-06 05:26:44 +0000104 Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000105 }
106
Benjamin Kramer46d311d2015-10-08 14:20:14 +0000107 IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem;
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000108 FileManager FileMgr;
109 IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
110 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
111 DiagnosticsEngine Diags;
112 SourceManager SourceMgr;
113 LangOptions LangOpts;
Alp Toker80758082014-07-06 05:26:44 +0000114 std::shared_ptr<TargetOptions> TargetOpts;
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000115 IntrusiveRefCntPtr<TargetInfo> Target;
116
117 // Register a header path as a known file and add its location
118 // to search path.
119 void AddFakeHeader(HeaderSearch& HeaderInfo, const char* HeaderPath,
120 bool IsSystemHeader) {
121 // Tell FileMgr about header.
Benjamin Kramer46d311d2015-10-08 14:20:14 +0000122 InMemoryFileSystem->addFile(HeaderPath, 0,
123 llvm::MemoryBuffer::getMemBuffer("\n"));
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000124
125 // Add header's parent path to search path.
Alexey Samsonovd1127d22014-10-15 22:00:40 +0000126 StringRef SearchPath = llvm::sys::path::parent_path(HeaderPath);
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000127 const DirectoryEntry *DE = FileMgr.getDirectory(SearchPath);
Daniel Dunbarae4feb62013-01-25 01:50:28 +0000128 DirectoryLookup DL(DE, SrcMgr::C_User, false);
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000129 HeaderInfo.AddSearchPath(DL, IsSystemHeader);
130 }
131
132 // Get the raw source string of the range.
133 StringRef GetSourceString(CharSourceRange Range) {
134 const char* B = SourceMgr.getCharacterData(Range.getBegin());
135 const char* E = SourceMgr.getCharacterData(Range.getEnd());
136
137 return StringRef(B, E - B);
138 }
139
140 // Run lexer over SourceText and collect FilenameRange from
141 // the InclusionDirective callback.
142 CharSourceRange InclusionDirectiveFilenameRange(const char* SourceText,
143 const char* HeaderPath, bool SystemHeader) {
Julie Hockett36d94ab2018-05-09 18:27:33 +0000144 return InclusionDirectiveCallback(SourceText, HeaderPath, SystemHeader)
145 ->FilenameRange;
146 }
147
148 InclusionDirectiveCallbacks *
149 InclusionDirectiveCallback(const char *SourceText, const char *HeaderPath,
150 bool SystemHeader) {
Alexey Samsonovd1127d22014-10-15 22:00:40 +0000151 std::unique_ptr<llvm::MemoryBuffer> Buf =
152 llvm::MemoryBuffer::getMemBuffer(SourceText);
David Blaikie50a5f972014-08-29 07:59:55 +0000153 SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000154
Richard Smith5d2ed482017-06-09 19:22:32 +0000155 TrivialModuleLoader ModLoader;
Duncan P. N. Exon Smith030d7d62017-03-20 17:58:26 +0000156 MemoryBufferCache PCMCache;
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000157
David Blaikie9c28cb32017-01-06 01:04:46 +0000158 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
159 Diags, LangOpts, Target.get());
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000160 AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
161
David Blaikiee3041682017-01-05 19:11:36 +0000162 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
Duncan P. N. Exon Smith030d7d62017-03-20 17:58:26 +0000163 SourceMgr, PCMCache, HeaderInfo, ModLoader,
Craig Topper416fa342014-06-08 08:38:12 +0000164 /*IILookup =*/nullptr,
Alp Toker96637802014-05-02 03:43:38 +0000165 /*OwnsHeaderSearch =*/false);
Alp Toker1ae02f62014-05-02 03:43:30 +0000166 PP.Initialize(*Target);
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000167 InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks;
Craig Topperb8a70532014-09-10 04:53:53 +0000168 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000169
170 // Lex source text.
171 PP.EnterMainSourceFile();
172
173 while (true) {
174 Token Tok;
175 PP.Lex(Tok);
176 if (Tok.is(tok::eof))
177 break;
178 }
179
180 // Callbacks have been executed at this point -- return filename range.
Julie Hockett36d94ab2018-05-09 18:27:33 +0000181 return Callbacks;
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000182 }
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000183
184 PragmaOpenCLExtensionCallbacks::CallbackParameters
185 PragmaOpenCLExtensionCall(const char* SourceText) {
186 LangOptions OpenCLLangOpts;
187 OpenCLLangOpts.OpenCL = 1;
188
Alexey Samsonovd1127d22014-10-15 22:00:40 +0000189 std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
190 llvm::MemoryBuffer::getMemBuffer(SourceText, "test.cl");
David Blaikie50a5f972014-08-29 07:59:55 +0000191 SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000192
Richard Smith5d2ed482017-06-09 19:22:32 +0000193 TrivialModuleLoader ModLoader;
Duncan P. N. Exon Smith030d7d62017-03-20 17:58:26 +0000194 MemoryBufferCache PCMCache;
David Blaikie9c28cb32017-01-06 01:04:46 +0000195 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
196 Diags, OpenCLLangOpts, Target.get());
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000197
David Blaikiee3041682017-01-05 19:11:36 +0000198 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags,
Duncan P. N. Exon Smith030d7d62017-03-20 17:58:26 +0000199 OpenCLLangOpts, SourceMgr, PCMCache, HeaderInfo, ModLoader,
David Blaikiee3041682017-01-05 19:11:36 +0000200 /*IILookup =*/nullptr,
Alp Toker1ae02f62014-05-02 03:43:30 +0000201 /*OwnsHeaderSearch =*/false);
202 PP.Initialize(*Target);
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000203
204 // parser actually sets correct pragma handlers for preprocessor
205 // according to LangOptions, so we init Parser to register opencl
206 // pragma handlers
Alp Toker08043432014-05-03 03:46:04 +0000207 ASTContext Context(OpenCLLangOpts, SourceMgr,
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000208 PP.getIdentifierTable(), PP.getSelectorTable(),
Alp Toker08043432014-05-03 03:46:04 +0000209 PP.getBuiltinInfo());
210 Context.InitBuiltinTypes(*Target);
211
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000212 ASTConsumer Consumer;
213 Sema S(PP, Context, Consumer);
214 Parser P(PP, S, false);
215 PragmaOpenCLExtensionCallbacks* Callbacks = new PragmaOpenCLExtensionCallbacks;
Craig Topperb8a70532014-09-10 04:53:53 +0000216 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000217
218 // Lex source text.
219 PP.EnterMainSourceFile();
220 while (true) {
221 Token Tok;
222 PP.Lex(Tok);
223 if (Tok.is(tok::eof))
224 break;
225 }
226
227 PragmaOpenCLExtensionCallbacks::CallbackParameters RetVal = {
Alexey Samsonov05747f32013-10-14 07:13:59 +0000228 Callbacks->Name,
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000229 Callbacks->State
230 };
231 return RetVal;
232 }
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000233};
234
Julie Hockett36d94ab2018-05-09 18:27:33 +0000235TEST_F(PPCallbacksTest, UserFileCharacteristics) {
236 const char *Source = "#include \"quoted.h\"\n";
237
238 SrcMgr::CharacteristicKind Kind =
239 InclusionDirectiveCallback(Source, "/quoted.h", false)->FileType;
240
241 ASSERT_EQ(SrcMgr::CharacteristicKind::C_User, Kind);
242}
243
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000244TEST_F(PPCallbacksTest, QuotedFilename) {
245 const char* Source =
246 "#include \"quoted.h\"\n";
247
248 CharSourceRange Range =
249 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
250
251 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
252}
253
254TEST_F(PPCallbacksTest, AngledFilename) {
255 const char* Source =
256 "#include <angled.h>\n";
257
258 CharSourceRange Range =
259 InclusionDirectiveFilenameRange(Source, "/angled.h", true);
260
261 ASSERT_EQ("<angled.h>", GetSourceString(Range));
262}
263
264TEST_F(PPCallbacksTest, QuotedInMacro) {
265 const char* Source =
266 "#define MACRO_QUOTED \"quoted.h\"\n"
267 "#include MACRO_QUOTED\n";
268
269 CharSourceRange Range =
270 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
271
272 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
273}
274
275TEST_F(PPCallbacksTest, AngledInMacro) {
276 const char* Source =
277 "#define MACRO_ANGLED <angled.h>\n"
278 "#include MACRO_ANGLED\n";
279
280 CharSourceRange Range =
281 InclusionDirectiveFilenameRange(Source, "/angled.h", true);
282
283 ASSERT_EQ("<angled.h>", GetSourceString(Range));
284}
285
286TEST_F(PPCallbacksTest, StringizedMacroArgument) {
287 const char* Source =
288 "#define MACRO_STRINGIZED(x) #x\n"
289 "#include MACRO_STRINGIZED(quoted.h)\n";
290
291 CharSourceRange Range =
292 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
293
294 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
295}
296
297TEST_F(PPCallbacksTest, ConcatenatedMacroArgument) {
298 const char* Source =
299 "#define MACRO_ANGLED <angled.h>\n"
300 "#define MACRO_CONCAT(x, y) x ## _ ## y\n"
301 "#include MACRO_CONCAT(MACRO, ANGLED)\n";
302
303 CharSourceRange Range =
304 InclusionDirectiveFilenameRange(Source, "/angled.h", false);
305
306 ASSERT_EQ("<angled.h>", GetSourceString(Range));
307}
308
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000309TEST_F(PPCallbacksTest, TrigraphFilename) {
310 const char* Source =
Benjamin Kramerf9db1302012-11-03 20:58:26 +0000311 "#include \"tri\?\?-graph.h\"\n";
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000312
313 CharSourceRange Range =
314 InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
315
Benjamin Kramerf9db1302012-11-03 20:58:26 +0000316 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000317}
318
319TEST_F(PPCallbacksTest, TrigraphInMacro) {
320 const char* Source =
Benjamin Kramerf9db1302012-11-03 20:58:26 +0000321 "#define MACRO_TRIGRAPH \"tri\?\?-graph.h\"\n"
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000322 "#include MACRO_TRIGRAPH\n";
323
324 CharSourceRange Range =
325 InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
326
Benjamin Kramerf9db1302012-11-03 20:58:26 +0000327 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
Argyrios Kyrtzidis2edbc862012-11-01 17:52:58 +0000328}
329
Pekka Jaaskelainen1db1da22013-10-12 09:29:48 +0000330TEST_F(PPCallbacksTest, OpenCLExtensionPragmaEnabled) {
331 const char* Source =
332 "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";
333
334 PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
335 PragmaOpenCLExtensionCall(Source);
336
337 ASSERT_EQ("cl_khr_fp64", Parameters.Name);
338 unsigned ExpectedState = 1;
339 ASSERT_EQ(ExpectedState, Parameters.State);
340}
341
342TEST_F(PPCallbacksTest, OpenCLExtensionPragmaDisabled) {
343 const char* Source =
344 "#pragma OPENCL EXTENSION cl_khr_fp16 : disable\n";
345
346 PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
347 PragmaOpenCLExtensionCall(Source);
348
349 ASSERT_EQ("cl_khr_fp16", Parameters.Name);
350 unsigned ExpectedState = 0;
351 ASSERT_EQ(ExpectedState, Parameters.State);
352}
353
Alexander Kornienkoab9db512015-06-22 23:07:51 +0000354} // anonoymous namespace