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