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