1 //===- 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"
19 #include "llvm/ADT/SmallString.h"
20 #include "llvm/Config/config.h"
21
22 #include "gtest/gtest.h"
23
24 using namespace llvm;
25 using namespace clang;
26
27 namespace {
28
29 // The test fixture.
30 class SourceManagerTest : public ::testing::Test {
31 protected:
SourceManagerTest()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;
43 IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
44 DiagnosticsEngine Diags;
45 SourceManager SourceMgr;
46 LangOptions LangOpts;
47 TargetOptions TargetOpts;
48 IntrusiveRefCntPtr<TargetInfo> Target;
49 };
50
51 class VoidModuleLoader : public ModuleLoader {
loadModule(SourceLocation ImportLoc,ModuleIdPath Path,Module::NameVisibilityKind Visibility,bool IsInclusionDirective)52 virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
53 Module::NameVisibilityKind Visibility,
54 bool IsInclusionDirective) {
55 return 0;
56 }
57 };
58
TEST_F(SourceManagerTest,isBeforeInTranslationUnit)59 TEST_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;
67 HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, &*Target);
68 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
100 SmallString<32> str;
101 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
110 #if defined(LLVM_ON_UNIX)
111
TEST_F(SourceManagerTest,getMacroArgExpandedLocation)112 TEST_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;
134 HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, &*Target);
135 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
179 namespace {
180
181 struct MacroAction {
182 SourceLocation Loc;
183 std::string Name;
184 bool isDefinition; // if false, it is expansion.
185
MacroAction__anonaed220990111::__anonaed220990211::MacroAction186 MacroAction(SourceLocation Loc, StringRef Name, bool isDefinition)
187 : Loc(Loc), Name(Name), isDefinition(isDefinition) { }
188 };
189
190 class MacroTracker : public PPCallbacks {
191 std::vector<MacroAction> &Macros;
192
193 public:
MacroTracker(std::vector<MacroAction> & Macros)194 explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) { }
195
MacroDefined(const Token & MacroNameTok,const MacroInfo * MI)196 virtual void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) {
197 Macros.push_back(MacroAction(MI->getDefinitionLoc(),
198 MacroNameTok.getIdentifierInfo()->getName(),
199 true));
200 }
MacroExpands(const Token & MacroNameTok,const MacroInfo * MI,SourceRange Range)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
TEST_F(SourceManagerTest,isBeforeInTranslationUnitWithMacroInInclude)211 TEST_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
294 #endif
295
296 } // anonymous namespace
297