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