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