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) override { }
47 GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
49 bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
53 // Stub to collect data from InclusionDirective callbacks.
54 class InclusionDirectiveCallbacks : public PPCallbacks {
56 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 {
61 this->HashLoc = HashLoc;
62 this->IncludeTok = IncludeTok;
63 this->FileName = FileName.str();
64 this->IsAngled = IsAngled;
65 this->FilenameRange = FilenameRange;
67 this->SearchPath = SearchPath.str();
68 this->RelativePath = RelativePath.str();
69 this->Imported = Imported;
72 SourceLocation HashLoc;
74 SmallString<16> FileName;
76 CharSourceRange FilenameRange;
77 const FileEntry* File;
78 SmallString<16> SearchPath;
79 SmallString<16> RelativePath;
80 const Module* Imported;
83 // Stub to collect data from PragmaOpenCLExtension callbacks.
84 class PragmaOpenCLExtensionCallbacks : public PPCallbacks {
91 PragmaOpenCLExtensionCallbacks() : Name("Not called."), State(99) {};
93 void PragmaOpenCLExtension(clang::SourceLocation NameLoc,
94 const clang::IdentifierInfo *Name,
95 clang::SourceLocation StateLoc,
96 unsigned State) override {
97 this->NameLoc = NameLoc;
98 this->Name = Name->getName();
99 this->StateLoc = StateLoc;
103 SourceLocation NameLoc;
104 SmallString<16> Name;
105 SourceLocation StateLoc;
109 // PPCallbacks test fixture.
110 class PPCallbacksTest : public ::testing::Test {
113 : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
114 DiagOpts(new DiagnosticOptions()),
115 Diags(DiagID, DiagOpts.get(), new IgnoringDiagConsumer()),
116 SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions()) {
117 TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
118 Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
121 FileSystemOptions FileMgrOpts;
123 IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
124 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
125 DiagnosticsEngine Diags;
126 SourceManager SourceMgr;
127 LangOptions LangOpts;
128 std::shared_ptr<TargetOptions> TargetOpts;
129 IntrusiveRefCntPtr<TargetInfo> Target;
131 // Register a header path as a known file and add its location
133 void AddFakeHeader(HeaderSearch& HeaderInfo, const char* HeaderPath,
134 bool IsSystemHeader) {
135 // Tell FileMgr about header.
136 FileMgr.getVirtualFile(HeaderPath, 0, 0);
138 // Add header's parent path to search path.
139 StringRef SearchPath = llvm::sys::path::parent_path(HeaderPath);
140 const DirectoryEntry *DE = FileMgr.getDirectory(SearchPath);
141 DirectoryLookup DL(DE, SrcMgr::C_User, false);
142 HeaderInfo.AddSearchPath(DL, IsSystemHeader);
145 // Get the raw source string of the range.
146 StringRef GetSourceString(CharSourceRange Range) {
147 const char* B = SourceMgr.getCharacterData(Range.getBegin());
148 const char* E = SourceMgr.getCharacterData(Range.getEnd());
150 return StringRef(B, E - B);
153 // Run lexer over SourceText and collect FilenameRange from
154 // the InclusionDirective callback.
155 CharSourceRange InclusionDirectiveFilenameRange(const char* SourceText,
156 const char* HeaderPath, bool SystemHeader) {
157 std::unique_ptr<llvm::MemoryBuffer> Buf =
158 llvm::MemoryBuffer::getMemBuffer(SourceText);
159 SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
161 VoidModuleLoader ModLoader;
163 IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts = new HeaderSearchOptions();
164 HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts,
166 AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
168 IntrusiveRefCntPtr<PreprocessorOptions> PPOpts = new PreprocessorOptions();
169 Preprocessor PP(PPOpts, Diags, LangOpts, SourceMgr, HeaderInfo, ModLoader,
170 /*IILookup =*/nullptr,
171 /*OwnsHeaderSearch =*/false);
172 PP.Initialize(*Target);
173 InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks;
174 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
177 PP.EnterMainSourceFile();
182 if (Tok.is(tok::eof))
186 // Callbacks have been executed at this point -- return filename range.
187 return Callbacks->FilenameRange;
190 PragmaOpenCLExtensionCallbacks::CallbackParameters
191 PragmaOpenCLExtensionCall(const char* SourceText) {
192 LangOptions OpenCLLangOpts;
193 OpenCLLangOpts.OpenCL = 1;
195 std::unique_ptr<llvm::MemoryBuffer> SourceBuf =
196 llvm::MemoryBuffer::getMemBuffer(SourceText, "test.cl");
197 SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(SourceBuf)));
199 VoidModuleLoader ModLoader;
200 HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags,
201 OpenCLLangOpts, Target.get());
203 Preprocessor PP(new PreprocessorOptions(), Diags, OpenCLLangOpts, SourceMgr,
204 HeaderInfo, ModLoader, /*IILookup =*/nullptr,
205 /*OwnsHeaderSearch =*/false);
206 PP.Initialize(*Target);
208 // parser actually sets correct pragma handlers for preprocessor
209 // according to LangOptions, so we init Parser to register opencl
211 ASTContext Context(OpenCLLangOpts, SourceMgr,
212 PP.getIdentifierTable(), PP.getSelectorTable(),
213 PP.getBuiltinInfo());
214 Context.InitBuiltinTypes(*Target);
216 ASTConsumer Consumer;
217 Sema S(PP, Context, Consumer);
218 Parser P(PP, S, false);
219 PragmaOpenCLExtensionCallbacks* Callbacks = new PragmaOpenCLExtensionCallbacks;
220 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(Callbacks));
223 PP.EnterMainSourceFile();
227 if (Tok.is(tok::eof))
231 PragmaOpenCLExtensionCallbacks::CallbackParameters RetVal = {
239 TEST_F(PPCallbacksTest, QuotedFilename) {
241 "#include \"quoted.h\"\n";
243 CharSourceRange Range =
244 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
246 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
249 TEST_F(PPCallbacksTest, AngledFilename) {
251 "#include <angled.h>\n";
253 CharSourceRange Range =
254 InclusionDirectiveFilenameRange(Source, "/angled.h", true);
256 ASSERT_EQ("<angled.h>", GetSourceString(Range));
259 TEST_F(PPCallbacksTest, QuotedInMacro) {
261 "#define MACRO_QUOTED \"quoted.h\"\n"
262 "#include MACRO_QUOTED\n";
264 CharSourceRange Range =
265 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
267 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
270 TEST_F(PPCallbacksTest, AngledInMacro) {
272 "#define MACRO_ANGLED <angled.h>\n"
273 "#include MACRO_ANGLED\n";
275 CharSourceRange Range =
276 InclusionDirectiveFilenameRange(Source, "/angled.h", true);
278 ASSERT_EQ("<angled.h>", GetSourceString(Range));
281 TEST_F(PPCallbacksTest, StringizedMacroArgument) {
283 "#define MACRO_STRINGIZED(x) #x\n"
284 "#include MACRO_STRINGIZED(quoted.h)\n";
286 CharSourceRange Range =
287 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
289 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
292 TEST_F(PPCallbacksTest, ConcatenatedMacroArgument) {
294 "#define MACRO_ANGLED <angled.h>\n"
295 "#define MACRO_CONCAT(x, y) x ## _ ## y\n"
296 "#include MACRO_CONCAT(MACRO, ANGLED)\n";
298 CharSourceRange Range =
299 InclusionDirectiveFilenameRange(Source, "/angled.h", false);
301 ASSERT_EQ("<angled.h>", GetSourceString(Range));
304 TEST_F(PPCallbacksTest, TrigraphFilename) {
306 "#include \"tri\?\?-graph.h\"\n";
308 CharSourceRange Range =
309 InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
311 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
314 TEST_F(PPCallbacksTest, TrigraphInMacro) {
316 "#define MACRO_TRIGRAPH \"tri\?\?-graph.h\"\n"
317 "#include MACRO_TRIGRAPH\n";
319 CharSourceRange Range =
320 InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
322 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
325 TEST_F(PPCallbacksTest, OpenCLExtensionPragmaEnabled) {
327 "#pragma OPENCL EXTENSION cl_khr_fp64 : enable\n";
329 PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
330 PragmaOpenCLExtensionCall(Source);
332 ASSERT_EQ("cl_khr_fp64", Parameters.Name);
333 unsigned ExpectedState = 1;
334 ASSERT_EQ(ExpectedState, Parameters.State);
337 TEST_F(PPCallbacksTest, OpenCLExtensionPragmaDisabled) {
339 "#pragma OPENCL EXTENSION cl_khr_fp16 : disable\n";
341 PragmaOpenCLExtensionCallbacks::CallbackParameters Parameters =
342 PragmaOpenCLExtensionCall(Source);
344 ASSERT_EQ("cl_khr_fp16", Parameters.Name);
345 unsigned ExpectedState = 0;
346 ASSERT_EQ(ExpectedState, Parameters.State);
349 } // anonoymous namespace