blob: 13104cbc0398c01e1358fc3e8ca69c2e7b19f90f [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"
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +000011#include "clang/Basic/Diagnostic.h"
12#include "clang/Basic/FileManager.h"
13#include "clang/Basic/LangOptions.h"
14#include "clang/Basic/SourceManager.h"
15#include "clang/Basic/TargetInfo.h"
16#include "clang/Basic/TargetOptions.h"
17#include "clang/Lex/HeaderSearch.h"
18#include "clang/Lex/HeaderSearchOptions.h"
19#include "clang/Lex/ModuleLoader.h"
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +000020#include "clang/Lex/PreprocessorOptions.h"
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +000021#include "llvm/ADT/SmallString.h"
22#include "llvm/Support/PathV2.h"
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +000023#include "gtest/gtest.h"
24
25using namespace llvm;
26using namespace llvm::sys;
27using namespace clang;
28
29namespace {
30
31// Stub out module loading.
32class VoidModuleLoader : public ModuleLoader {
Douglas Gregor7dff05b2012-11-30 00:01:57 +000033 virtual ModuleLoadResult loadModule(SourceLocation ImportLoc,
34 ModuleIdPath Path,
35 Module::NameVisibilityKind Visibility,
36 bool IsInclusionDirective) {
37 return ModuleLoadResult();
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +000038 }
NAKAMURA Takumi1a4191d2013-01-12 02:16:29 +000039
40 virtual void makeModuleVisible(Module *Mod,
Argyrios Kyrtzidis5ebcb202013-02-01 16:36:12 +000041 Module::NameVisibilityKind Visibility,
42 SourceLocation ImportLoc) { }
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +000043};
44
45// Stub to collect data from InclusionDirective callbacks.
46class InclusionDirectiveCallbacks : public PPCallbacks {
47public:
48 void InclusionDirective(SourceLocation HashLoc,
49 const Token &IncludeTok,
50 StringRef FileName,
51 bool IsAngled,
52 CharSourceRange FilenameRange,
53 const FileEntry *File,
54 StringRef SearchPath,
55 StringRef RelativePath,
56 const Module *Imported) {
57 this->HashLoc = HashLoc;
58 this->IncludeTok = IncludeTok;
59 this->FileName = FileName.str();
60 this->IsAngled = IsAngled;
61 this->FilenameRange = FilenameRange;
62 this->File = File;
63 this->SearchPath = SearchPath.str();
64 this->RelativePath = RelativePath.str();
65 this->Imported = Imported;
66 }
67
68 SourceLocation HashLoc;
69 Token IncludeTok;
70 SmallString<16> FileName;
71 bool IsAngled;
72 CharSourceRange FilenameRange;
73 const FileEntry* File;
74 SmallString<16> SearchPath;
75 SmallString<16> RelativePath;
76 const Module* Imported;
77};
78
79// PPCallbacks test fixture.
80class PPCallbacksTest : public ::testing::Test {
81protected:
82 PPCallbacksTest()
83 : FileMgr(FileMgrOpts),
84 DiagID(new DiagnosticIDs()),
85 DiagOpts(new DiagnosticOptions()),
86 Diags(DiagID, DiagOpts.getPtr(), new IgnoringDiagConsumer()),
87 SourceMgr(Diags, FileMgr) {
88 TargetOpts = new TargetOptions();
89 TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
NAKAMURA Takumi3a4c8cf2012-11-16 04:40:11 +000090 Target = TargetInfo::CreateTargetInfo(Diags, &*TargetOpts);
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +000091 }
92
93 FileSystemOptions FileMgrOpts;
94 FileManager FileMgr;
95 IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
96 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
97 DiagnosticsEngine Diags;
98 SourceManager SourceMgr;
99 LangOptions LangOpts;
100 IntrusiveRefCntPtr<TargetOptions> TargetOpts;
101 IntrusiveRefCntPtr<TargetInfo> Target;
102
103 // Register a header path as a known file and add its location
104 // to search path.
105 void AddFakeHeader(HeaderSearch& HeaderInfo, const char* HeaderPath,
106 bool IsSystemHeader) {
107 // Tell FileMgr about header.
108 FileMgr.getVirtualFile(HeaderPath, 0, 0);
109
110 // Add header's parent path to search path.
111 StringRef SearchPath = path::parent_path(HeaderPath);
112 const DirectoryEntry *DE = FileMgr.getDirectory(SearchPath);
Daniel Dunbar1ea6bc02013-01-25 01:50:28 +0000113 DirectoryLookup DL(DE, SrcMgr::C_User, false);
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000114 HeaderInfo.AddSearchPath(DL, IsSystemHeader);
115 }
116
117 // Get the raw source string of the range.
118 StringRef GetSourceString(CharSourceRange Range) {
119 const char* B = SourceMgr.getCharacterData(Range.getBegin());
120 const char* E = SourceMgr.getCharacterData(Range.getEnd());
121
122 return StringRef(B, E - B);
123 }
124
125 // Run lexer over SourceText and collect FilenameRange from
126 // the InclusionDirective callback.
127 CharSourceRange InclusionDirectiveFilenameRange(const char* SourceText,
128 const char* HeaderPath, bool SystemHeader) {
129 MemoryBuffer *Buf = MemoryBuffer::getMemBuffer(SourceText);
130 (void)SourceMgr.createMainFileIDForMemBuffer(Buf);
131
132 VoidModuleLoader ModLoader;
133
134 IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts = new HeaderSearchOptions();
135 HeaderSearch HeaderInfo(HSOpts, FileMgr, Diags, LangOpts, Target.getPtr());
136 AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader);
137
138 IntrusiveRefCntPtr<PreprocessorOptions> PPOpts = new PreprocessorOptions();
139 Preprocessor PP(PPOpts, Diags, LangOpts,
140 Target.getPtr(),
141 SourceMgr, HeaderInfo, ModLoader,
142 /*IILookup =*/ 0,
143 /*OwnsHeaderSearch =*/false,
144 /*DelayInitialization =*/ false);
145 InclusionDirectiveCallbacks* Callbacks = new InclusionDirectiveCallbacks;
146 PP.addPPCallbacks(Callbacks); // Takes ownership.
147
148 // Lex source text.
149 PP.EnterMainSourceFile();
150
151 while (true) {
152 Token Tok;
153 PP.Lex(Tok);
154 if (Tok.is(tok::eof))
155 break;
156 }
157
158 // Callbacks have been executed at this point -- return filename range.
159 return Callbacks->FilenameRange;
160 }
161};
162
163TEST_F(PPCallbacksTest, QuotedFilename) {
164 const char* Source =
165 "#include \"quoted.h\"\n";
166
167 CharSourceRange Range =
168 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
169
170 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
171}
172
173TEST_F(PPCallbacksTest, AngledFilename) {
174 const char* Source =
175 "#include <angled.h>\n";
176
177 CharSourceRange Range =
178 InclusionDirectiveFilenameRange(Source, "/angled.h", true);
179
180 ASSERT_EQ("<angled.h>", GetSourceString(Range));
181}
182
183TEST_F(PPCallbacksTest, QuotedInMacro) {
184 const char* Source =
185 "#define MACRO_QUOTED \"quoted.h\"\n"
186 "#include MACRO_QUOTED\n";
187
188 CharSourceRange Range =
189 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
190
191 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
192}
193
194TEST_F(PPCallbacksTest, AngledInMacro) {
195 const char* Source =
196 "#define MACRO_ANGLED <angled.h>\n"
197 "#include MACRO_ANGLED\n";
198
199 CharSourceRange Range =
200 InclusionDirectiveFilenameRange(Source, "/angled.h", true);
201
202 ASSERT_EQ("<angled.h>", GetSourceString(Range));
203}
204
205TEST_F(PPCallbacksTest, StringizedMacroArgument) {
206 const char* Source =
207 "#define MACRO_STRINGIZED(x) #x\n"
208 "#include MACRO_STRINGIZED(quoted.h)\n";
209
210 CharSourceRange Range =
211 InclusionDirectiveFilenameRange(Source, "/quoted.h", false);
212
213 ASSERT_EQ("\"quoted.h\"", GetSourceString(Range));
214}
215
216TEST_F(PPCallbacksTest, ConcatenatedMacroArgument) {
217 const char* Source =
218 "#define MACRO_ANGLED <angled.h>\n"
219 "#define MACRO_CONCAT(x, y) x ## _ ## y\n"
220 "#include MACRO_CONCAT(MACRO, ANGLED)\n";
221
222 CharSourceRange Range =
223 InclusionDirectiveFilenameRange(Source, "/angled.h", false);
224
225 ASSERT_EQ("<angled.h>", GetSourceString(Range));
226}
227
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000228TEST_F(PPCallbacksTest, TrigraphFilename) {
229 const char* Source =
Benjamin Kramer71640952012-11-03 20:58:26 +0000230 "#include \"tri\?\?-graph.h\"\n";
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000231
232 CharSourceRange Range =
233 InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
234
Benjamin Kramer71640952012-11-03 20:58:26 +0000235 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000236}
237
238TEST_F(PPCallbacksTest, TrigraphInMacro) {
239 const char* Source =
Benjamin Kramer71640952012-11-03 20:58:26 +0000240 "#define MACRO_TRIGRAPH \"tri\?\?-graph.h\"\n"
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000241 "#include MACRO_TRIGRAPH\n";
242
243 CharSourceRange Range =
244 InclusionDirectiveFilenameRange(Source, "/tri~graph.h", false);
245
Benjamin Kramer71640952012-11-03 20:58:26 +0000246 ASSERT_EQ("\"tri\?\?-graph.h\"", GetSourceString(Range));
Argyrios Kyrtzidiscfa1caa2012-11-01 17:52:58 +0000247}
248
249} // anonoymous namespace