blob: 429b58d7ea4523ae427419da037e980e09d50336 [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"
13#include "clang/Basic/LangOptions.h"
14#include "clang/Basic/TargetOptions.h"
15#include "clang/Basic/TargetInfo.h"
16#include "clang/Lex/ModuleLoader.h"
17#include "clang/Lex/HeaderSearch.h"
18#include "clang/Lex/Preprocessor.h"
Benjamin Kramer8fe83e12012-02-04 13:45:25 +000019#include "llvm/ADT/SmallString.h"
Argyrios Kyrtzidiscee5ec92011-12-21 16:56:35 +000020#include "llvm/Config/config.h"
Argyrios Kyrtzidisd7711ec2011-12-21 16:56:29 +000021
22#include "gtest/gtest.h"
23
24using namespace llvm;
25using namespace clang;
26
27namespace {
28
29// The test fixture.
30class SourceManagerTest : public ::testing::Test {
31protected:
32 SourceManagerTest()
33 : FileMgr(FileMgrOpts),
34 DiagID(new DiagnosticIDs()),
35 Diags(DiagID, new IgnoringDiagConsumer()),
36 SourceMgr(Diags, FileMgr) {
37 TargetOpts.Triple = "x86_64-apple-darwin11.1.0";
38 Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
39 }
40
41 FileSystemOptions FileMgrOpts;
42 FileManager FileMgr;
Dylan Noblesmithc93dc782012-02-20 14:00:23 +000043 IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
Argyrios Kyrtzidisd7711ec2011-12-21 16:56:29 +000044 DiagnosticsEngine Diags;
45 SourceManager SourceMgr;
46 LangOptions LangOpts;
47 TargetOptions TargetOpts;
Dylan Noblesmithc93dc782012-02-20 14:00:23 +000048 IntrusiveRefCntPtr<TargetInfo> Target;
Argyrios Kyrtzidisd7711ec2011-12-21 16:56:29 +000049};
50
51class VoidModuleLoader : public ModuleLoader {
52 virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
53 Module::NameVisibilityKind Visibility,
54 bool IsInclusionDirective) {
55 return 0;
56 }
57};
58
59TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
60 const char *source =
61 "#define M(x) [x]\n"
62 "M(foo)";
63 MemoryBuffer *buf = MemoryBuffer::getMemBuffer(source);
64 FileID mainFileID = SourceMgr.createMainFileIDForMemBuffer(buf);
65
66 VoidModuleLoader ModLoader;
Douglas Gregordc58aa72012-01-30 06:01:29 +000067 HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, &*Target);
Argyrios Kyrtzidisd7711ec2011-12-21 16:56:29 +000068 Preprocessor PP(Diags, LangOpts,
69 Target.getPtr(),
70 SourceMgr, HeaderInfo, ModLoader,
71 /*IILookup =*/ 0,
72 /*OwnsHeaderSearch =*/false,
73 /*DelayInitialization =*/ false);
74 PP.EnterMainSourceFile();
75
76 std::vector<Token> toks;
77 while (1) {
78 Token tok;
79 PP.Lex(tok);
80 if (tok.is(tok::eof))
81 break;
82 toks.push_back(tok);
83 }
84
85 // Make sure we got the tokens that we expected.
86 ASSERT_EQ(3U, toks.size());
87 ASSERT_EQ(tok::l_square, toks[0].getKind());
88 ASSERT_EQ(tok::identifier, toks[1].getKind());
89 ASSERT_EQ(tok::r_square, toks[2].getKind());
90
91 SourceLocation lsqrLoc = toks[0].getLocation();
92 SourceLocation idLoc = toks[1].getLocation();
93 SourceLocation rsqrLoc = toks[2].getLocation();
94
95 SourceLocation macroExpStartLoc = SourceMgr.translateLineCol(mainFileID, 2, 1);
96 SourceLocation macroExpEndLoc = SourceMgr.translateLineCol(mainFileID, 2, 6);
97 ASSERT_TRUE(macroExpStartLoc.isFileID());
98 ASSERT_TRUE(macroExpEndLoc.isFileID());
99
Dylan Noblesmith36d59272012-02-13 12:32:26 +0000100 SmallString<32> str;
Argyrios Kyrtzidisd7711ec2011-12-21 16:56:29 +0000101 ASSERT_EQ("M", PP.getSpelling(macroExpStartLoc, str));
102 ASSERT_EQ(")", PP.getSpelling(macroExpEndLoc, str));
103
104 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(lsqrLoc, idLoc));
105 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, rsqrLoc));
106 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(macroExpStartLoc, idLoc));
107 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, macroExpEndLoc));
108}
109
Argyrios Kyrtzidiscee5ec92011-12-21 16:56:35 +0000110#if defined(LLVM_ON_UNIX)
111
112TEST_F(SourceManagerTest, getMacroArgExpandedLocation) {
113 const char *header =
114 "#define FM(x,y) x\n";
115
116 const char *main =
117 "#include \"/test-header.h\"\n"
118 "#define VAL 0\n"
119 "FM(VAL,0)\n"
120 "FM(0,VAL)\n"
121 "FM(FM(0,VAL),0)\n"
122 "#define CONCAT(X, Y) X##Y\n"
123 "CONCAT(1,1)\n";
124
125 MemoryBuffer *headerBuf = MemoryBuffer::getMemBuffer(header);
126 MemoryBuffer *mainBuf = MemoryBuffer::getMemBuffer(main);
127 FileID mainFileID = SourceMgr.createMainFileIDForMemBuffer(mainBuf);
128
129 const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h",
130 headerBuf->getBufferSize(), 0);
131 SourceMgr.overrideFileContents(headerFile, headerBuf);
132
133 VoidModuleLoader ModLoader;
Douglas Gregordc58aa72012-01-30 06:01:29 +0000134 HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, &*Target);
Argyrios Kyrtzidiscee5ec92011-12-21 16:56:35 +0000135 Preprocessor PP(Diags, LangOpts,
136 Target.getPtr(),
137 SourceMgr, HeaderInfo, ModLoader,
138 /*IILookup =*/ 0,
139 /*OwnsHeaderSearch =*/false,
140 /*DelayInitialization =*/ false);
141 PP.EnterMainSourceFile();
142
143 std::vector<Token> toks;
144 while (1) {
145 Token tok;
146 PP.Lex(tok);
147 if (tok.is(tok::eof))
148 break;
149 toks.push_back(tok);
150 }
151
152 // Make sure we got the tokens that we expected.
153 ASSERT_EQ(4U, toks.size());
154 ASSERT_EQ(tok::numeric_constant, toks[0].getKind());
155 ASSERT_EQ(tok::numeric_constant, toks[1].getKind());
156 ASSERT_EQ(tok::numeric_constant, toks[2].getKind());
157 ASSERT_EQ(tok::numeric_constant, toks[3].getKind());
158
159 SourceLocation defLoc = SourceMgr.translateLineCol(mainFileID, 2, 13);
160 SourceLocation loc1 = SourceMgr.translateLineCol(mainFileID, 3, 8);
161 SourceLocation loc2 = SourceMgr.translateLineCol(mainFileID, 4, 4);
162 SourceLocation loc3 = SourceMgr.translateLineCol(mainFileID, 5, 7);
163 SourceLocation defLoc2 = SourceMgr.translateLineCol(mainFileID, 6, 22);
164 defLoc = SourceMgr.getMacroArgExpandedLocation(defLoc);
165 loc1 = SourceMgr.getMacroArgExpandedLocation(loc1);
166 loc2 = SourceMgr.getMacroArgExpandedLocation(loc2);
167 loc3 = SourceMgr.getMacroArgExpandedLocation(loc3);
168 defLoc2 = SourceMgr.getMacroArgExpandedLocation(defLoc2);
169
170 EXPECT_TRUE(defLoc.isFileID());
171 EXPECT_TRUE(loc1.isFileID());
172 EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc2));
173 EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc3));
174 EXPECT_EQ(loc2, toks[1].getLocation());
175 EXPECT_EQ(loc3, toks[2].getLocation());
176 EXPECT_TRUE(defLoc2.isFileID());
177}
178
Argyrios Kyrtzidisdb81d382012-03-27 18:47:48 +0000179namespace {
180
181struct MacroAction {
182 SourceLocation Loc;
183 std::string Name;
184 bool isDefinition; // if false, it is expansion.
185
186 MacroAction(SourceLocation Loc, StringRef Name, bool isDefinition)
187 : Loc(Loc), Name(Name), isDefinition(isDefinition) { }
188};
189
190class MacroTracker : public PPCallbacks {
191 std::vector<MacroAction> &Macros;
192
193public:
194 explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) { }
195
196 virtual void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) {
197 Macros.push_back(MacroAction(MI->getDefinitionLoc(),
198 MacroNameTok.getIdentifierInfo()->getName(),
199 true));
200 }
201 virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo* MI,
202 SourceRange Range) {
203 Macros.push_back(MacroAction(MacroNameTok.getLocation(),
204 MacroNameTok.getIdentifierInfo()->getName(),
205 false));
206 }
207};
208
209}
210
211TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
212 const char *header =
213 "#define MACRO_IN_INCLUDE 0\n";
214
215 const char *main =
216 "#define M(x) x\n"
217 "#define INC \"/test-header.h\"\n"
218 "#include M(INC)\n"
219 "#define INC2 </test-header.h>\n"
220 "#include M(INC2)\n";
221
222 MemoryBuffer *headerBuf = MemoryBuffer::getMemBuffer(header);
223 MemoryBuffer *mainBuf = MemoryBuffer::getMemBuffer(main);
224 SourceMgr.createMainFileIDForMemBuffer(mainBuf);
225
226 const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h",
227 headerBuf->getBufferSize(), 0);
228 SourceMgr.overrideFileContents(headerFile, headerBuf);
229
230 VoidModuleLoader ModLoader;
231 HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, &*Target);
232 Preprocessor PP(Diags, LangOpts,
233 Target.getPtr(),
234 SourceMgr, HeaderInfo, ModLoader,
235 /*IILookup =*/ 0,
236 /*OwnsHeaderSearch =*/false,
237 /*DelayInitialization =*/ false);
238
239 std::vector<MacroAction> Macros;
240 PP.addPPCallbacks(new MacroTracker(Macros));
241
242 PP.EnterMainSourceFile();
243
244 std::vector<Token> toks;
245 while (1) {
246 Token tok;
247 PP.Lex(tok);
248 if (tok.is(tok::eof))
249 break;
250 toks.push_back(tok);
251 }
252
253 // Make sure we got the tokens that we expected.
254 ASSERT_EQ(0U, toks.size());
255
256 ASSERT_EQ(9U, Macros.size());
257 // #define M(x) x
258 ASSERT_TRUE(Macros[0].isDefinition);
259 ASSERT_EQ("M", Macros[0].Name);
260 // #define INC "/test-header.h"
261 ASSERT_TRUE(Macros[1].isDefinition);
262 ASSERT_EQ("INC", Macros[1].Name);
263 // M expansion in #include M(INC)
264 ASSERT_FALSE(Macros[2].isDefinition);
265 ASSERT_EQ("M", Macros[2].Name);
266 // INC expansion in #include M(INC)
267 ASSERT_FALSE(Macros[3].isDefinition);
268 ASSERT_EQ("INC", Macros[3].Name);
269 // #define MACRO_IN_INCLUDE 0
270 ASSERT_TRUE(Macros[4].isDefinition);
271 ASSERT_EQ("MACRO_IN_INCLUDE", Macros[4].Name);
272 // #define INC2 </test-header.h>
273 ASSERT_TRUE(Macros[5].isDefinition);
274 ASSERT_EQ("INC2", Macros[5].Name);
275 // M expansion in #include M(INC2)
276 ASSERT_FALSE(Macros[6].isDefinition);
277 ASSERT_EQ("M", Macros[6].Name);
278 // INC2 expansion in #include M(INC2)
279 ASSERT_FALSE(Macros[7].isDefinition);
280 ASSERT_EQ("INC2", Macros[7].Name);
281 // #define MACRO_IN_INCLUDE 0
282 ASSERT_TRUE(Macros[8].isDefinition);
283 ASSERT_EQ("MACRO_IN_INCLUDE", Macros[8].Name);
284
285 // The INC expansion in #include M(INC) comes before the first
286 // MACRO_IN_INCLUDE definition of the included file.
287 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[3].Loc, Macros[4].Loc));
288
289 // The INC2 expansion in #include M(INC2) comes before the second
290 // MACRO_IN_INCLUDE definition of the included file.
291 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[7].Loc, Macros[8].Loc));
292}
293
Argyrios Kyrtzidiscee5ec92011-12-21 16:56:35 +0000294#endif
295
Argyrios Kyrtzidisd7711ec2011-12-21 16:56:29 +0000296} // anonymous namespace