1 //===- unittests/Lex/PPCallbacksTest.cpp - PPCallbacks tests ------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===--------------------------------------------------------------===//
10 #include "clang/Lex/Preprocessor.h"
11 #include "clang/AST/ASTConsumer.h"
12 #include "clang/AST/ASTContext.h"
13 #include "clang/Basic/Diagnostic.h"
14 #include "clang/Basic/DiagnosticOptions.h"
15 #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"
23 #include "clang/Lex/PreprocessorOptions.h"
24 #include "clang/Parse/Parser.h"
25 #include "clang/Sema/Sema.h"
26 #include "llvm/ADT/SmallString.h"
27 #include "llvm/Support/Path.h"
28 #include "gtest/gtest.h"
30 using namespace clang
;
34 // Stub out module loading.
35 class VoidModuleLoader
: public ModuleLoader
{
36 ModuleLoadResult
loadModule(SourceLocation ImportLoc
,
38 Module::NameVisibilityKind Visibility
,
39 bool IsInclusionDirective
) override
{
40 return ModuleLoadResult();
43 void makeModuleVisible(Module
*Mod
,
44 Module::NameVisibilityKind Visibility
,
45 SourceLocation ImportLoc
,
46 bool Complain
) override
{ }
48 GlobalModuleIndex
*loadGlobalModuleIndex(SourceLocation TriggerLoc
) override
50 bool lookupMissingImports(StringRef Name
, SourceLocation TriggerLoc
) override
54 // Stub to collect data from InclusionDirective callbacks.
55 class InclusionDirectiveCallbacks
: public PPCallbacks
{
57 void InclusionDirective(SourceLocation HashLoc
,
58 const Token
&IncludeTok
,
61 CharSourceRange FilenameRange
,
62 const FileEntry
*File
,
64 StringRef RelativePath
,
65 const Module
*Imported
) {
66 this->HashLoc
= HashLoc
;
67 this->IncludeTok
= IncludeTok
;
68 this->FileName
= FileName
.str();
69 this->IsAngled
= IsAngled
;
70 this->FilenameRange
= FilenameRange
;
72 this->SearchPath
= SearchPath
.str();
73 this->RelativePath
= RelativePath
.str();
74 this->Imported
= Imported
;
77 SourceLocation HashLoc
;
79 SmallString
<16> FileName
;
81 CharSourceRange FilenameRange
;
82 const FileEntry
* File
;
83 SmallString
<16> SearchPath
;
84 SmallString
<16> RelativePath
;
85 const Module
* Imported
;
88 // Stub to collect data from PragmaOpenCLExtension callbacks.
89 class PragmaOpenCLExtensionCallbacks
: public PPCallbacks
{
96 PragmaOpenCLExtensionCallbacks() : Name("Not called."), State(99) {};
98 void PragmaOpenCLExtension(
99 clang::SourceLocation NameLoc
, const clang::IdentifierInfo
*Name
,
100 clang::SourceLocation StateLoc
, unsigned State
) {
101 this->NameLoc
= NameLoc
;
102 this->Name
= Name
->getName();
103 this->StateLoc
= StateLoc
;
107 SourceLocation NameLoc
;
108 SmallString
<16> Name
;
109 SourceLocation StateLoc
;
113 // PPCallbacks test fixture.
114 class PPCallbacksTest
: public ::testing::Test
{
117 : FileMgr(FileMgrOpts
), DiagID(new DiagnosticIDs()),
118 DiagOpts(new DiagnosticOptions()),
119 Diags(DiagID
, DiagOpts
.get(), new IgnoringDiagConsumer()),
120 SourceMgr(Diags
, FileMgr
), TargetOpts(new TargetOptions()) {
121 TargetOpts
->Triple
= "x86_64-apple-darwin11.1.0";
122 Target
= TargetInfo::CreateTargetInfo(Diags
, TargetOpts
);
125 FileSystemOptions FileMgrOpts
;
127 IntrusiveRefCntPtr
<DiagnosticIDs
> DiagID
;
128 IntrusiveRefCntPtr
<DiagnosticOptions
> DiagOpts
;
129 DiagnosticsEngine Diags
;
130 SourceManager SourceMgr
;
131 LangOptions LangOpts
;
132 std::shared_ptr
<TargetOptions
> TargetOpts
;
133 IntrusiveRefCntPtr
<TargetInfo
> Target
;
135 // Register a header path as a known file and add its location
137 void AddFakeHeader(HeaderSearch
& HeaderInfo
, const char* HeaderPath
,
138 bool IsSystemHeader
) {
139 // Tell FileMgr about header.
140 FileMgr
.getVirtualFile(HeaderPath
, 0, 0);
142 // Add header's parent path to search path.
143 StringRef SearchPath
= llvm::sys::path::parent_path(HeaderPath
);
144 const DirectoryEntry
*DE
= FileMgr
.getDirectory(SearchPath
);
145 DirectoryLookup
DL(DE
, SrcMgr::C_User
, false);
146 HeaderInfo
.AddSearchPath(DL
, IsSystemHeader
);
149 // Get the raw source string of the range.
150 StringRef
GetSourceString(CharSourceRange Range
) {
151 const char* B
= SourceMgr
.getCharacterData(Range
.getBegin());
152 const char* E
= SourceMgr
.getCharacterData(Range
.getEnd());
154 return StringRef(B
, E
- B
);
157 // Run lexer over SourceText and collect FilenameRange from
158 // the InclusionDirective callback.
159 CharSourceRange
InclusionDirectiveFilenameRange(const char* SourceText
,
160 const char* HeaderPath
, bool SystemHeader
) {
161 std::unique_ptr
<llvm::MemoryBuffer
> Buf
=
162 llvm::MemoryBuffer::getMemBuffer(SourceText
);
163 SourceMgr
.setMainFileID(SourceMgr
.createFileID(std::move(Buf
)));
165 VoidModuleLoader ModLoader
;
167 IntrusiveRefCntPtr
<HeaderSearchOptions
> HSOpts
= new HeaderSearchOptions();
168 HeaderSearch
HeaderInfo(HSOpts
, SourceMgr
, Diags
, LangOpts
,
170 AddFakeHeader(HeaderInfo
, HeaderPath
, SystemHeader
);
172 IntrusiveRefCntPtr
<PreprocessorOptions
> PPOpts
= new PreprocessorOptions();
173 Preprocessor
PP(PPOpts
, Diags
, LangOpts
, SourceMgr
, HeaderInfo
, ModLoader
,
174 /*IILookup =*/nullptr,
175 /*OwnsHeaderSearch =*/false);
176 PP
.Initialize(*Target
);
177 InclusionDirectiveCallbacks
* Callbacks
= new InclusionDirectiveCallbacks
;
178 PP
.addPPCallbacks(std::unique_ptr
<PPCallbacks
>(Callbacks
));
181 PP
.EnterMainSourceFile();
186 if (Tok
.is(tok::eof
))
190 // Callbacks have been executed at this point -- return filename range.
191 return Callbacks
->FilenameRange
;
194 PragmaOpenCLExtensionCallbacks::CallbackParameters
195 PragmaOpenCLExtensionCall(const char* SourceText
) {
196 LangOptions OpenCLLangOpts
;
197 OpenCLLangOpts
.OpenCL
= 1;
199 std::unique_ptr
<llvm::MemoryBuffer
> SourceBuf
=
200 llvm::MemoryBuffer::getMemBuffer(SourceText
, "test.cl");
201 SourceMgr
.setMainFileID(SourceMgr
.createFileID(std::move(SourceBuf
)));
203 VoidModuleLoader ModLoader
;
204 HeaderSearch
HeaderInfo(new HeaderSearchOptions
, SourceMgr
, Diags
,
205 OpenCLLangOpts
, Target
.get());
207 Preprocessor
PP(new PreprocessorOptions(), Diags
, OpenCLLangOpts
, SourceMgr
,
208 HeaderInfo
, ModLoader
, /*IILookup =*/nullptr,
209 /*OwnsHeaderSearch =*/false);
210 PP
.Initialize(*Target
);
212 // parser actually sets correct pragma handlers for preprocessor
213 // according to LangOptions, so we init Parser to register opencl
215 ASTContext
Context(OpenCLLangOpts
, SourceMgr
,
216 PP
.getIdentifierTable(), PP
.getSelectorTable(),
217 PP
.getBuiltinInfo());
218 Context
.InitBuiltinTypes(*Target
);
220 ASTConsumer Consumer
;
221 Sema
S(PP
, Context
, Consumer
);
222 Parser
P(PP
, S
, false);
223 PragmaOpenCLExtensionCallbacks
* Callbacks
= new PragmaOpenCLExtensionCallbacks
;
224 PP
.addPPCallbacks(std::unique_ptr
<PPCallbacks
>(Callbacks
));
227 PP
.EnterMainSourceFile();
231 if (Tok
.is(tok::eof
))
235 PragmaOpenCLExtensionCallbacks::CallbackParameters RetVal
= {
243 TEST_F(PPCallbacksTest
, QuotedFilename
) {
245 "#include \"quoted.h\"\n";
247 CharSourceRange Range
=
248 InclusionDirectiveFilenameRange(Source
, "/quoted.h", false);
250 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range
));
253 TEST_F(PPCallbacksTest
, AngledFilename
) {
255 "#include <angled.h>\n";
257 CharSourceRange Range
=
258 InclusionDirectiveFilenameRange(Source
, "/angled.h", true);
260 ASSERT_EQ("<angled.h>", GetSourceString(Range
));
263 TEST_F(PPCallbacksTest
, QuotedInMacro
) {
265 "#define MACRO_QUOTED \"quoted.h\"\n"
266 "#include MACRO_QUOTED\n";
268 CharSourceRange Range
=
269 InclusionDirectiveFilenameRange(Source
, "/quoted.h", false);
271 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range
));
274 TEST_F(PPCallbacksTest
, AngledInMacro
) {
276 "#define MACRO_ANGLED <angled.h>\n"
277 "#include MACRO_ANGLED\n";
279 CharSourceRange Range
=
280 InclusionDirectiveFilenameRange(Source
, "/angled.h", true);
282 ASSERT_EQ("<angled.h>", GetSourceString(Range
));
285 TEST_F(PPCallbacksTest
, StringizedMacroArgument
) {
287 "#define MACRO_STRINGIZED(x) #x\n"
288 "#include MACRO_STRINGIZED(quoted.h)\n";
290 CharSourceRange Range
=
291 InclusionDirectiveFilenameRange(Source
, "/quoted.h", false);
293 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range
));
296 TEST_F(PPCallbacksTest
, ConcatenatedMacroArgument
) {
298 "#define MACRO_ANGLED <angled.h>\n"
299 "#define MACRO_CONCAT(x, y) x ## _ ## y\n"
300 "#include MACRO_CONCAT(MACRO, ANGLED)\n";
302 CharSourceRange Range
=
303 InclusionDirectiveFilenameRange(Source
, "/angled.h", false);
305 ASSERT_EQ("<angled.h>", GetSourceString(Range
));
308 TEST_F(PPCallbacksTest
, TrigraphFilename
) {
310 "#include \"tri\?\?-graph.h\"\n";
312 CharSourceRange Range
=
313 InclusionDirectiveFilenameRange(Source
, "/tri~graph.h", false);
315 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range
));
318 TEST_F(PPCallbacksTest
, TrigraphInMacro
) {
320 "#define MACRO_TRIGRAPH \"tri\?\?-graph.h\"\n"
321 "#include MACRO_TRIGRAPH\n";
323 CharSourceRange Range
=
324 InclusionDirectiveFilenameRange(Source
, "/tri~graph.h", false);
326 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range
));
329 TEST_F(PPCallbacksTest
, OpenCLExtensionPragmaEnabled
) {
331 "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";
333 PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters
=
334 PragmaOpenCLExtensionCall(Source
);
336 ASSERT_EQ("cl_khr_fp64", Parameters
.Name
);
337 unsigned ExpectedState
= 1;
338 ASSERT_EQ(ExpectedState
, Parameters
.State
);
341 TEST_F(PPCallbacksTest
, OpenCLExtensionPragmaDisabled
) {
343 "#pragma OPENCL EXTENSION cl_khr_fp16 : disable\n";
345 PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters
=
346 PragmaOpenCLExtensionCall(Source
);
348 ASSERT_EQ("cl_khr_fp16", Parameters
.Name
);
349 unsigned ExpectedState
= 0;
350 ASSERT_EQ(ExpectedState
, Parameters
.State
);
353 } // anonoymous namespace