blob: 477645d7a026210b598c477a2424643060c9cc8c [file] [log] [blame]
Argyrios Kyrtzidisd7711ec2011-12-21 16:56:29 +00001//===- unittests/Basic/SourceManagerTest.cpp ------ SourceManager 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/SourceManager.h"
11#include "clang/Basic/FileManager.h"
12#include "clang/Basic/Diagnostic.h"
Douglas Gregor3aeb34f2012-10-23 22:38:58 +000013#include "clang/Basic/DiagnosticOptions.h"
Argyrios Kyrtzidisd7711ec2011-12-21 16:56:29 +000014#include "clang/Basic/LangOptions.h"
15#include "clang/Basic/TargetOptions.h"
16#include "clang/Basic/TargetInfo.h"
17#include "clang/Lex/ModuleLoader.h"
18#include "clang/Lex/HeaderSearch.h"
Douglas Gregorb0985c82012-10-24 16:24:38 +000019#include "clang/Lex/HeaderSearchOptions.h"
Argyrios Kyrtzidisd7711ec2011-12-21 16:56:29 +000020#include "clang/Lex/Preprocessor.h"
Douglas Gregor36a16492012-10-24 17:46:57 +000021#include "clang/Lex/PreprocessorOptions.h"
Benjamin Kramer8fe83e12012-02-04 13:45:25 +000022#include "llvm/ADT/SmallString.h"
Argyrios Kyrtzidiscee5ec92011-12-21 16:56:35 +000023#include "llvm/Config/config.h"
Argyrios Kyrtzidisd7711ec2011-12-21 16:56:29 +000024
25#include "gtest/gtest.h"
26
27using namespace llvm;
28using namespace clang;
29
30namespace {
31
32// The test fixture.
33class SourceManagerTest : public ::testing::Test {
34protected:
35 SourceManagerTest()
36 : FileMgr(FileMgrOpts),
37 DiagID(new DiagnosticIDs()),
Douglas Gregor8e023612012-10-23 22:31:51 +000038 Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
Douglas Gregor07f8cf42012-10-17 00:11:35 +000039 SourceMgr(Diags, FileMgr),
40 TargetOpts(new TargetOptions) {
41 TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
NAKAMURA Takumi3a4c8cf2012-11-16 04:40:11 +000042 Target = TargetInfo::CreateTargetInfo(Diags, &*TargetOpts);
Argyrios Kyrtzidisd7711ec2011-12-21 16:56:29 +000043 }
44
45 FileSystemOptions FileMgrOpts;
46 FileManager FileMgr;
Dylan Noblesmithc93dc782012-02-20 14:00:23 +000047 IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
Argyrios Kyrtzidisd7711ec2011-12-21 16:56:29 +000048 DiagnosticsEngine Diags;
49 SourceManager SourceMgr;
50 LangOptions LangOpts;
Douglas Gregor07f8cf42012-10-17 00:11:35 +000051 IntrusiveRefCntPtr<TargetOptions> TargetOpts;
Dylan Noblesmithc93dc782012-02-20 14:00:23 +000052 IntrusiveRefCntPtr<TargetInfo> Target;
Argyrios Kyrtzidisd7711ec2011-12-21 16:56:29 +000053};
54
55class VoidModuleLoader : public ModuleLoader {
Douglas Gregor7dff05b2012-11-30 00:01:57 +000056 virtual ModuleLoadResult loadModule(SourceLocation ImportLoc,
57 ModuleIdPath Path,
58 Module::NameVisibilityKind Visibility,
59 bool IsInclusionDirective) {
60 return ModuleLoadResult();
Argyrios Kyrtzidisd7711ec2011-12-21 16:56:29 +000061 }
62};
63
64TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
65 const char *source =
66 "#define M(x) [x]\n"
67 "M(foo)";
68 MemoryBuffer *buf = MemoryBuffer::getMemBuffer(source);
69 FileID mainFileID = SourceMgr.createMainFileIDForMemBuffer(buf);
70
71 VoidModuleLoader ModLoader;
Douglas Gregorb0985c82012-10-24 16:24:38 +000072 HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts,
73 &*Target);
Douglas Gregor36a16492012-10-24 17:46:57 +000074 Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(),
Argyrios Kyrtzidisd7711ec2011-12-21 16:56:29 +000075 SourceMgr, HeaderInfo, ModLoader,
76 /*IILookup =*/ 0,
77 /*OwnsHeaderSearch =*/false,
78 /*DelayInitialization =*/ false);
79 PP.EnterMainSourceFile();
80
81 std::vector<Token> toks;
82 while (1) {
83 Token tok;
84 PP.Lex(tok);
85 if (tok.is(tok::eof))
86 break;
87 toks.push_back(tok);
88 }
89
90 // Make sure we got the tokens that we expected.
91 ASSERT_EQ(3U, toks.size());
92 ASSERT_EQ(tok::l_square, toks[0].getKind());
93 ASSERT_EQ(tok::identifier, toks[1].getKind());
94 ASSERT_EQ(tok::r_square, toks[2].getKind());
95
96 SourceLocation lsqrLoc = toks[0].getLocation();
97 SourceLocation idLoc = toks[1].getLocation();
98 SourceLocation rsqrLoc = toks[2].getLocation();
99
100 SourceLocation macroExpStartLoc = SourceMgr.translateLineCol(mainFileID, 2, 1);
101 SourceLocation macroExpEndLoc = SourceMgr.translateLineCol(mainFileID, 2, 6);
102 ASSERT_TRUE(macroExpStartLoc.isFileID());
103 ASSERT_TRUE(macroExpEndLoc.isFileID());
104
Dylan Noblesmith36d59272012-02-13 12:32:26 +0000105 SmallString<32> str;
Argyrios Kyrtzidisd7711ec2011-12-21 16:56:29 +0000106 ASSERT_EQ("M", PP.getSpelling(macroExpStartLoc, str));
107 ASSERT_EQ(")", PP.getSpelling(macroExpEndLoc, str));
108
109 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(lsqrLoc, idLoc));
110 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, rsqrLoc));
111 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(macroExpStartLoc, idLoc));
112 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, macroExpEndLoc));
113}
114
Jordan Rose2e413f92012-06-19 03:09:38 +0000115TEST_F(SourceManagerTest, getColumnNumber) {
116 const char *Source =
117 "int x;\n"
118 "int y;";
119
120 MemoryBuffer *Buf = MemoryBuffer::getMemBuffer(Source);
121 FileID MainFileID = SourceMgr.createMainFileIDForMemBuffer(Buf);
122
123 bool Invalid;
124
125 Invalid = false;
126 EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 0, &Invalid));
127 EXPECT_TRUE(!Invalid);
128
129 Invalid = false;
130 EXPECT_EQ(5U, SourceMgr.getColumnNumber(MainFileID, 4, &Invalid));
131 EXPECT_TRUE(!Invalid);
132
133 Invalid = false;
134 EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 7, &Invalid));
135 EXPECT_TRUE(!Invalid);
136
137 Invalid = false;
138 EXPECT_EQ(5U, SourceMgr.getColumnNumber(MainFileID, 11, &Invalid));
139 EXPECT_TRUE(!Invalid);
140
141 Invalid = false;
142 EXPECT_EQ(7U, SourceMgr.getColumnNumber(MainFileID, strlen(Source),
143 &Invalid));
144 EXPECT_TRUE(!Invalid);
145
146 Invalid = false;
147 SourceMgr.getColumnNumber(MainFileID, strlen(Source)+1, &Invalid);
148 EXPECT_TRUE(Invalid);
149
150 // Test invalid files
151 Invalid = false;
152 SourceMgr.getColumnNumber(FileID(), 0, &Invalid);
153 EXPECT_TRUE(Invalid);
154
155 Invalid = false;
156 SourceMgr.getColumnNumber(FileID(), 1, &Invalid);
157 EXPECT_TRUE(Invalid);
158
159 // Test with no invalid flag.
160 EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 0, NULL));
161}
162
Argyrios Kyrtzidiscee5ec92011-12-21 16:56:35 +0000163#if defined(LLVM_ON_UNIX)
164
165TEST_F(SourceManagerTest, getMacroArgExpandedLocation) {
166 const char *header =
167 "#define FM(x,y) x\n";
168
169 const char *main =
170 "#include \"/test-header.h\"\n"
171 "#define VAL 0\n"
172 "FM(VAL,0)\n"
173 "FM(0,VAL)\n"
174 "FM(FM(0,VAL),0)\n"
175 "#define CONCAT(X, Y) X##Y\n"
176 "CONCAT(1,1)\n";
177
178 MemoryBuffer *headerBuf = MemoryBuffer::getMemBuffer(header);
179 MemoryBuffer *mainBuf = MemoryBuffer::getMemBuffer(main);
180 FileID mainFileID = SourceMgr.createMainFileIDForMemBuffer(mainBuf);
181
182 const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h",
183 headerBuf->getBufferSize(), 0);
184 SourceMgr.overrideFileContents(headerFile, headerBuf);
185
186 VoidModuleLoader ModLoader;
Douglas Gregorb0985c82012-10-24 16:24:38 +0000187 HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts,
188 &*Target);
Douglas Gregor36a16492012-10-24 17:46:57 +0000189 Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(),
Argyrios Kyrtzidiscee5ec92011-12-21 16:56:35 +0000190 SourceMgr, HeaderInfo, ModLoader,
191 /*IILookup =*/ 0,
192 /*OwnsHeaderSearch =*/false,
193 /*DelayInitialization =*/ false);
194 PP.EnterMainSourceFile();
195
196 std::vector<Token> toks;
197 while (1) {
198 Token tok;
199 PP.Lex(tok);
200 if (tok.is(tok::eof))
201 break;
202 toks.push_back(tok);
203 }
204
205 // Make sure we got the tokens that we expected.
206 ASSERT_EQ(4U, toks.size());
207 ASSERT_EQ(tok::numeric_constant, toks[0].getKind());
208 ASSERT_EQ(tok::numeric_constant, toks[1].getKind());
209 ASSERT_EQ(tok::numeric_constant, toks[2].getKind());
210 ASSERT_EQ(tok::numeric_constant, toks[3].getKind());
211
212 SourceLocation defLoc = SourceMgr.translateLineCol(mainFileID, 2, 13);
213 SourceLocation loc1 = SourceMgr.translateLineCol(mainFileID, 3, 8);
214 SourceLocation loc2 = SourceMgr.translateLineCol(mainFileID, 4, 4);
215 SourceLocation loc3 = SourceMgr.translateLineCol(mainFileID, 5, 7);
216 SourceLocation defLoc2 = SourceMgr.translateLineCol(mainFileID, 6, 22);
217 defLoc = SourceMgr.getMacroArgExpandedLocation(defLoc);
218 loc1 = SourceMgr.getMacroArgExpandedLocation(loc1);
219 loc2 = SourceMgr.getMacroArgExpandedLocation(loc2);
220 loc3 = SourceMgr.getMacroArgExpandedLocation(loc3);
221 defLoc2 = SourceMgr.getMacroArgExpandedLocation(defLoc2);
222
223 EXPECT_TRUE(defLoc.isFileID());
224 EXPECT_TRUE(loc1.isFileID());
225 EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc2));
226 EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc3));
227 EXPECT_EQ(loc2, toks[1].getLocation());
228 EXPECT_EQ(loc3, toks[2].getLocation());
229 EXPECT_TRUE(defLoc2.isFileID());
230}
231
Argyrios Kyrtzidisdb81d382012-03-27 18:47:48 +0000232namespace {
233
234struct MacroAction {
235 SourceLocation Loc;
236 std::string Name;
237 bool isDefinition; // if false, it is expansion.
238
239 MacroAction(SourceLocation Loc, StringRef Name, bool isDefinition)
240 : Loc(Loc), Name(Name), isDefinition(isDefinition) { }
241};
242
243class MacroTracker : public PPCallbacks {
244 std::vector<MacroAction> &Macros;
245
246public:
247 explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) { }
248
249 virtual void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) {
250 Macros.push_back(MacroAction(MI->getDefinitionLoc(),
251 MacroNameTok.getIdentifierInfo()->getName(),
252 true));
253 }
254 virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo* MI,
255 SourceRange Range) {
256 Macros.push_back(MacroAction(MacroNameTok.getLocation(),
257 MacroNameTok.getIdentifierInfo()->getName(),
258 false));
259 }
260};
261
262}
263
264TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
265 const char *header =
266 "#define MACRO_IN_INCLUDE 0\n";
267
268 const char *main =
269 "#define M(x) x\n"
270 "#define INC \"/test-header.h\"\n"
271 "#include M(INC)\n"
272 "#define INC2 </test-header.h>\n"
273 "#include M(INC2)\n";
274
275 MemoryBuffer *headerBuf = MemoryBuffer::getMemBuffer(header);
276 MemoryBuffer *mainBuf = MemoryBuffer::getMemBuffer(main);
277 SourceMgr.createMainFileIDForMemBuffer(mainBuf);
278
279 const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h",
280 headerBuf->getBufferSize(), 0);
281 SourceMgr.overrideFileContents(headerFile, headerBuf);
282
283 VoidModuleLoader ModLoader;
Douglas Gregorb0985c82012-10-24 16:24:38 +0000284 HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts,
285 &*Target);
Douglas Gregor36a16492012-10-24 17:46:57 +0000286 Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(),
Argyrios Kyrtzidisdb81d382012-03-27 18:47:48 +0000287 SourceMgr, HeaderInfo, ModLoader,
288 /*IILookup =*/ 0,
289 /*OwnsHeaderSearch =*/false,
290 /*DelayInitialization =*/ false);
291
292 std::vector<MacroAction> Macros;
293 PP.addPPCallbacks(new MacroTracker(Macros));
294
295 PP.EnterMainSourceFile();
296
297 std::vector<Token> toks;
298 while (1) {
299 Token tok;
300 PP.Lex(tok);
301 if (tok.is(tok::eof))
302 break;
303 toks.push_back(tok);
304 }
305
306 // Make sure we got the tokens that we expected.
307 ASSERT_EQ(0U, toks.size());
308
309 ASSERT_EQ(9U, Macros.size());
310 // #define M(x) x
311 ASSERT_TRUE(Macros[0].isDefinition);
312 ASSERT_EQ("M", Macros[0].Name);
313 // #define INC "/test-header.h"
314 ASSERT_TRUE(Macros[1].isDefinition);
315 ASSERT_EQ("INC", Macros[1].Name);
316 // M expansion in #include M(INC)
317 ASSERT_FALSE(Macros[2].isDefinition);
318 ASSERT_EQ("M", Macros[2].Name);
319 // INC expansion in #include M(INC)
320 ASSERT_FALSE(Macros[3].isDefinition);
321 ASSERT_EQ("INC", Macros[3].Name);
322 // #define MACRO_IN_INCLUDE 0
323 ASSERT_TRUE(Macros[4].isDefinition);
324 ASSERT_EQ("MACRO_IN_INCLUDE", Macros[4].Name);
325 // #define INC2 </test-header.h>
326 ASSERT_TRUE(Macros[5].isDefinition);
327 ASSERT_EQ("INC2", Macros[5].Name);
328 // M expansion in #include M(INC2)
329 ASSERT_FALSE(Macros[6].isDefinition);
330 ASSERT_EQ("M", Macros[6].Name);
331 // INC2 expansion in #include M(INC2)
332 ASSERT_FALSE(Macros[7].isDefinition);
333 ASSERT_EQ("INC2", Macros[7].Name);
334 // #define MACRO_IN_INCLUDE 0
335 ASSERT_TRUE(Macros[8].isDefinition);
336 ASSERT_EQ("MACRO_IN_INCLUDE", Macros[8].Name);
337
338 // The INC expansion in #include M(INC) comes before the first
339 // MACRO_IN_INCLUDE definition of the included file.
340 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[3].Loc, Macros[4].Loc));
341
342 // The INC2 expansion in #include M(INC2) comes before the second
343 // MACRO_IN_INCLUDE definition of the included file.
344 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[7].Loc, Macros[8].Loc));
345}
346
Argyrios Kyrtzidiscee5ec92011-12-21 16:56:35 +0000347#endif
348
Argyrios Kyrtzidisd7711ec2011-12-21 16:56:29 +0000349} // anonymous namespace