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