1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | #include "clang/Basic/SourceManager.h" |
10 | #include "clang/Basic/Diagnostic.h" |
11 | #include "clang/Basic/DiagnosticOptions.h" |
12 | #include "clang/Basic/FileManager.h" |
13 | #include "clang/Basic/LangOptions.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 | #include "llvm/ADT/SmallString.h" |
22 | #include "llvm/Config/llvm-config.h" |
23 | #include "gtest/gtest.h" |
24 | |
25 | using namespace clang; |
26 | |
27 | namespace { |
28 | |
29 | |
30 | class SourceManagerTest : public ::testing::Test { |
31 | protected: |
32 | SourceManagerTest() |
33 | : FileMgr(FileMgrOpts), |
34 | DiagID(new DiagnosticIDs()), |
35 | Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()), |
36 | SourceMgr(Diags, FileMgr), |
37 | TargetOpts(new TargetOptions) { |
38 | TargetOpts->Triple = "x86_64-apple-darwin11.1.0"; |
39 | Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts); |
40 | } |
41 | |
42 | FileSystemOptions FileMgrOpts; |
43 | FileManager FileMgr; |
44 | IntrusiveRefCntPtr<DiagnosticIDs> DiagID; |
45 | DiagnosticsEngine Diags; |
46 | SourceManager SourceMgr; |
47 | LangOptions LangOpts; |
48 | std::shared_ptr<TargetOptions> TargetOpts; |
49 | IntrusiveRefCntPtr<TargetInfo> Target; |
50 | }; |
51 | |
52 | TEST_F(SourceManagerTest, isBeforeInTranslationUnit) { |
53 | const char *source = |
54 | "#define M(x) [x]\n" |
55 | "M(foo)"; |
56 | std::unique_ptr<llvm::MemoryBuffer> Buf = |
57 | llvm::MemoryBuffer::getMemBuffer(source); |
58 | FileID mainFileID = SourceMgr.createFileID(std::move(Buf)); |
59 | SourceMgr.setMainFileID(mainFileID); |
60 | |
61 | TrivialModuleLoader ModLoader; |
62 | HeaderSearch (std::make_shared<HeaderSearchOptions>(), SourceMgr, |
63 | Diags, LangOpts, &*Target); |
64 | Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts, |
65 | SourceMgr, HeaderInfo, ModLoader, |
66 | , |
67 | ); |
68 | PP.Initialize(*Target); |
69 | PP.EnterMainSourceFile(); |
70 | |
71 | std::vector<Token> toks; |
72 | while (1) { |
73 | Token tok; |
74 | PP.Lex(tok); |
75 | if (tok.is(tok::eof)) |
76 | break; |
77 | toks.push_back(tok); |
78 | } |
79 | |
80 | |
81 | ASSERT_EQ(3U, toks.size()); |
82 | ASSERT_EQ(tok::l_square, toks[0].getKind()); |
83 | ASSERT_EQ(tok::identifier, toks[1].getKind()); |
84 | ASSERT_EQ(tok::r_square, toks[2].getKind()); |
85 | |
86 | SourceLocation lsqrLoc = toks[0].getLocation(); |
87 | SourceLocation idLoc = toks[1].getLocation(); |
88 | SourceLocation rsqrLoc = toks[2].getLocation(); |
89 | |
90 | SourceLocation macroExpStartLoc = SourceMgr.translateLineCol(mainFileID, 2, 1); |
91 | SourceLocation macroExpEndLoc = SourceMgr.translateLineCol(mainFileID, 2, 6); |
92 | ASSERT_TRUE(macroExpStartLoc.isFileID()); |
93 | ASSERT_TRUE(macroExpEndLoc.isFileID()); |
94 | |
95 | SmallString<32> str; |
96 | ASSERT_EQ("M", PP.getSpelling(macroExpStartLoc, str)); |
97 | ASSERT_EQ(")", PP.getSpelling(macroExpEndLoc, str)); |
98 | |
99 | EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(lsqrLoc, idLoc)); |
100 | EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, rsqrLoc)); |
101 | EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(macroExpStartLoc, idLoc)); |
102 | EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, macroExpEndLoc)); |
103 | } |
104 | |
105 | TEST_F(SourceManagerTest, getColumnNumber) { |
106 | const char *Source = |
107 | "int x;\n" |
108 | "int y;"; |
109 | |
110 | std::unique_ptr<llvm::MemoryBuffer> Buf = |
111 | llvm::MemoryBuffer::getMemBuffer(Source); |
112 | FileID MainFileID = SourceMgr.createFileID(std::move(Buf)); |
113 | SourceMgr.setMainFileID(MainFileID); |
114 | |
115 | bool Invalid; |
116 | |
117 | Invalid = false; |
118 | EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 0, &Invalid)); |
119 | EXPECT_TRUE(!Invalid); |
120 | |
121 | Invalid = false; |
122 | EXPECT_EQ(5U, SourceMgr.getColumnNumber(MainFileID, 4, &Invalid)); |
123 | EXPECT_TRUE(!Invalid); |
124 | |
125 | Invalid = false; |
126 | EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 7, &Invalid)); |
127 | EXPECT_TRUE(!Invalid); |
128 | |
129 | Invalid = false; |
130 | EXPECT_EQ(5U, SourceMgr.getColumnNumber(MainFileID, 11, &Invalid)); |
131 | EXPECT_TRUE(!Invalid); |
132 | |
133 | Invalid = false; |
134 | EXPECT_EQ(7U, SourceMgr.getColumnNumber(MainFileID, strlen(Source), |
135 | &Invalid)); |
136 | EXPECT_TRUE(!Invalid); |
137 | |
138 | Invalid = false; |
139 | SourceMgr.getColumnNumber(MainFileID, strlen(Source)+1, &Invalid); |
140 | EXPECT_TRUE(Invalid); |
141 | |
142 | |
143 | Invalid = false; |
144 | SourceMgr.getColumnNumber(FileID(), 0, &Invalid); |
145 | EXPECT_TRUE(Invalid); |
146 | |
147 | Invalid = false; |
148 | SourceMgr.getColumnNumber(FileID(), 1, &Invalid); |
149 | EXPECT_TRUE(Invalid); |
150 | |
151 | |
152 | EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 0, nullptr)); |
153 | } |
154 | |
155 | TEST_F(SourceManagerTest, locationPrintTest) { |
156 | const char * = "#define IDENTITY(x) x\n"; |
157 | |
158 | const char *Source = "int x;\n" |
159 | "include \"test-header.h\"\n" |
160 | "IDENTITY(int y);\n" |
161 | "int z;"; |
162 | |
163 | std::unique_ptr<llvm::MemoryBuffer> = |
164 | llvm::MemoryBuffer::getMemBuffer(header); |
165 | std::unique_ptr<llvm::MemoryBuffer> Buf = |
166 | llvm::MemoryBuffer::getMemBuffer(Source); |
167 | |
168 | const FileEntry *SourceFile = |
169 | FileMgr.getVirtualFile("/mainFile.cpp", Buf->getBufferSize(), 0); |
170 | SourceMgr.overrideFileContents(SourceFile, std::move(Buf)); |
171 | |
172 | const FileEntry * = |
173 | FileMgr.getVirtualFile("/test-header.h", HeaderBuf->getBufferSize(), 0); |
174 | SourceMgr.overrideFileContents(HeaderFile, std::move(HeaderBuf)); |
175 | |
176 | FileID MainFileID = SourceMgr.getOrCreateFileID(SourceFile, SrcMgr::C_User); |
177 | FileID = SourceMgr.getOrCreateFileID(HeaderFile, SrcMgr::C_User); |
178 | SourceMgr.setMainFileID(MainFileID); |
179 | |
180 | auto BeginLoc = SourceMgr.getLocForStartOfFile(MainFileID); |
181 | auto EndLoc = SourceMgr.getLocForEndOfFile(MainFileID); |
182 | |
183 | auto BeginEOLLoc = SourceMgr.translateLineCol(MainFileID, 1, 7); |
184 | |
185 | auto = SourceMgr.getLocForStartOfFile(HeaderFileID); |
186 | |
187 | EXPECT_EQ(BeginLoc.printToString(SourceMgr), "/mainFile.cpp:1:1"); |
188 | EXPECT_EQ(EndLoc.printToString(SourceMgr), "/mainFile.cpp:4:7"); |
189 | |
190 | EXPECT_EQ(BeginEOLLoc.printToString(SourceMgr), "/mainFile.cpp:1:7"); |
191 | EXPECT_EQ(HeaderLoc.printToString(SourceMgr), "/test-header.h:1:1"); |
192 | |
193 | EXPECT_EQ(SourceRange(BeginLoc, BeginLoc).printToString(SourceMgr), |
194 | "</mainFile.cpp:1:1>"); |
195 | EXPECT_EQ(SourceRange(BeginLoc, BeginEOLLoc).printToString(SourceMgr), |
196 | "</mainFile.cpp:1:1, col:7>"); |
197 | EXPECT_EQ(SourceRange(BeginLoc, EndLoc).printToString(SourceMgr), |
198 | "</mainFile.cpp:1:1, line:4:7>"); |
199 | EXPECT_EQ(SourceRange(BeginLoc, HeaderLoc).printToString(SourceMgr), |
200 | "</mainFile.cpp:1:1, /test-header.h:1:1>"); |
201 | } |
202 | |
203 | #if defined(LLVM_ON_UNIX) |
204 | |
205 | TEST_F(SourceManagerTest, getMacroArgExpandedLocation) { |
206 | const char *header = |
207 | "#define FM(x,y) x\n"; |
208 | |
209 | const char *main = |
210 | "#include \"/test-header.h\"\n" |
211 | "#define VAL 0\n" |
212 | "FM(VAL,0)\n" |
213 | "FM(0,VAL)\n" |
214 | "FM(FM(0,VAL),0)\n" |
215 | "#define CONCAT(X, Y) X##Y\n" |
216 | "CONCAT(1,1)\n"; |
217 | |
218 | std::unique_ptr<llvm::MemoryBuffer> HeaderBuf = |
219 | llvm::MemoryBuffer::getMemBuffer(header); |
220 | std::unique_ptr<llvm::MemoryBuffer> MainBuf = |
221 | llvm::MemoryBuffer::getMemBuffer(main); |
222 | FileID mainFileID = SourceMgr.createFileID(std::move(MainBuf)); |
223 | SourceMgr.setMainFileID(mainFileID); |
224 | |
225 | const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h", |
226 | HeaderBuf->getBufferSize(), 0); |
227 | SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf)); |
228 | |
229 | TrivialModuleLoader ModLoader; |
230 | HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr, |
231 | Diags, LangOpts, &*Target); |
232 | Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts, |
233 | SourceMgr, HeaderInfo, ModLoader, |
234 | , |
235 | ); |
236 | PP.Initialize(*Target); |
237 | PP.EnterMainSourceFile(); |
238 | |
239 | std::vector<Token> toks; |
240 | while (1) { |
241 | Token tok; |
242 | PP.Lex(tok); |
243 | if (tok.is(tok::eof)) |
244 | break; |
245 | toks.push_back(tok); |
246 | } |
247 | |
248 | |
249 | ASSERT_EQ(4U, toks.size()); |
250 | ASSERT_EQ(tok::numeric_constant, toks[0].getKind()); |
251 | ASSERT_EQ(tok::numeric_constant, toks[1].getKind()); |
252 | ASSERT_EQ(tok::numeric_constant, toks[2].getKind()); |
253 | ASSERT_EQ(tok::numeric_constant, toks[3].getKind()); |
254 | |
255 | SourceLocation defLoc = SourceMgr.translateLineCol(mainFileID, 2, 13); |
256 | SourceLocation loc1 = SourceMgr.translateLineCol(mainFileID, 3, 8); |
257 | SourceLocation loc2 = SourceMgr.translateLineCol(mainFileID, 4, 4); |
258 | SourceLocation loc3 = SourceMgr.translateLineCol(mainFileID, 5, 7); |
259 | SourceLocation defLoc2 = SourceMgr.translateLineCol(mainFileID, 6, 22); |
260 | defLoc = SourceMgr.getMacroArgExpandedLocation(defLoc); |
261 | loc1 = SourceMgr.getMacroArgExpandedLocation(loc1); |
262 | loc2 = SourceMgr.getMacroArgExpandedLocation(loc2); |
263 | loc3 = SourceMgr.getMacroArgExpandedLocation(loc3); |
264 | defLoc2 = SourceMgr.getMacroArgExpandedLocation(defLoc2); |
265 | |
266 | EXPECT_TRUE(defLoc.isFileID()); |
267 | EXPECT_TRUE(loc1.isFileID()); |
268 | EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc2)); |
269 | EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc3)); |
270 | EXPECT_EQ(loc2, toks[1].getLocation()); |
271 | EXPECT_EQ(loc3, toks[2].getLocation()); |
272 | EXPECT_TRUE(defLoc2.isFileID()); |
273 | } |
274 | |
275 | namespace { |
276 | |
277 | struct MacroAction { |
278 | enum Kind { kExpansion, kDefinition, kUnDefinition}; |
279 | |
280 | SourceLocation Loc; |
281 | std::string Name; |
282 | unsigned MAKind : 3; |
283 | |
284 | MacroAction(SourceLocation Loc, StringRef Name, unsigned K) |
285 | : Loc(Loc), Name(Name), MAKind(K) { } |
286 | |
287 | bool isExpansion() const { return MAKind == kExpansion; } |
288 | bool isDefinition() const { return MAKind & kDefinition; } |
289 | bool isUnDefinition() const { return MAKind & kUnDefinition; } |
290 | }; |
291 | |
292 | class MacroTracker : public PPCallbacks { |
293 | std::vector<MacroAction> &Macros; |
294 | |
295 | public: |
296 | explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) { } |
297 | |
298 | void MacroDefined(const Token &MacroNameTok, |
299 | const MacroDirective *MD) override { |
300 | Macros.push_back(MacroAction(MD->getLocation(), |
301 | MacroNameTok.getIdentifierInfo()->getName(), |
302 | MacroAction::kDefinition)); |
303 | } |
304 | void MacroUndefined(const Token &MacroNameTok, |
305 | const MacroDefinition &MD, |
306 | const MacroDirective *UD) override { |
307 | Macros.push_back( |
308 | MacroAction(UD ? UD->getLocation() : SourceLocation(), |
309 | MacroNameTok.getIdentifierInfo()->getName(), |
310 | UD ? MacroAction::kDefinition | MacroAction::kUnDefinition |
311 | : MacroAction::kUnDefinition)); |
312 | } |
313 | void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, |
314 | SourceRange Range, const MacroArgs *Args) override { |
315 | Macros.push_back(MacroAction(MacroNameTok.getLocation(), |
316 | MacroNameTok.getIdentifierInfo()->getName(), |
317 | MacroAction::kExpansion)); |
318 | } |
319 | }; |
320 | |
321 | } |
322 | |
323 | TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) { |
324 | const char *header = |
325 | "#define MACRO_IN_INCLUDE 0\n" |
326 | "#define MACRO_DEFINED\n" |
327 | "#undef MACRO_DEFINED\n" |
328 | "#undef MACRO_UNDEFINED\n"; |
329 | |
330 | const char *main = |
331 | "#define M(x) x\n" |
332 | "#define INC \"/test-header.h\"\n" |
333 | "#include M(INC)\n" |
334 | "#define INC2 </test-header.h>\n" |
335 | "#include M(INC2)\n"; |
336 | |
337 | std::unique_ptr<llvm::MemoryBuffer> HeaderBuf = |
338 | llvm::MemoryBuffer::getMemBuffer(header); |
339 | std::unique_ptr<llvm::MemoryBuffer> MainBuf = |
340 | llvm::MemoryBuffer::getMemBuffer(main); |
341 | SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(MainBuf))); |
342 | |
343 | const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h", |
344 | HeaderBuf->getBufferSize(), 0); |
345 | SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf)); |
346 | |
347 | TrivialModuleLoader ModLoader; |
348 | HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr, |
349 | Diags, LangOpts, &*Target); |
350 | Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts, |
351 | SourceMgr, HeaderInfo, ModLoader, |
352 | , |
353 | ); |
354 | PP.Initialize(*Target); |
355 | |
356 | std::vector<MacroAction> Macros; |
357 | PP.addPPCallbacks(llvm::make_unique<MacroTracker>(Macros)); |
358 | |
359 | PP.EnterMainSourceFile(); |
360 | |
361 | std::vector<Token> toks; |
362 | while (1) { |
363 | Token tok; |
364 | PP.Lex(tok); |
365 | if (tok.is(tok::eof)) |
366 | break; |
367 | toks.push_back(tok); |
368 | } |
369 | |
370 | |
371 | ASSERT_EQ(0U, toks.size()); |
372 | |
373 | ASSERT_EQ(15U, Macros.size()); |
374 | |
375 | ASSERT_TRUE(Macros[0].isDefinition()); |
376 | ASSERT_EQ("M", Macros[0].Name); |
377 | |
378 | ASSERT_TRUE(Macros[1].isDefinition()); |
379 | ASSERT_EQ("INC", Macros[1].Name); |
380 | |
381 | ASSERT_FALSE(Macros[2].isDefinition()); |
382 | ASSERT_EQ("M", Macros[2].Name); |
383 | |
384 | ASSERT_TRUE(Macros[3].isExpansion()); |
385 | ASSERT_EQ("INC", Macros[3].Name); |
386 | |
387 | ASSERT_TRUE(Macros[4].isDefinition()); |
388 | ASSERT_EQ("MACRO_IN_INCLUDE", Macros[4].Name); |
389 | |
390 | ASSERT_TRUE(Macros[5].isDefinition()); |
391 | ASSERT_FALSE(Macros[5].isUnDefinition()); |
392 | ASSERT_EQ("MACRO_DEFINED", Macros[5].Name); |
393 | |
394 | ASSERT_TRUE(Macros[6].isDefinition()); |
395 | ASSERT_TRUE(Macros[6].isUnDefinition()); |
396 | ASSERT_EQ("MACRO_DEFINED", Macros[6].Name); |
397 | |
398 | ASSERT_FALSE(Macros[7].isDefinition()); |
399 | ASSERT_TRUE(Macros[7].isUnDefinition()); |
400 | ASSERT_EQ("MACRO_UNDEFINED", Macros[7].Name); |
401 | |
402 | ASSERT_TRUE(Macros[8].isDefinition()); |
403 | ASSERT_EQ("INC2", Macros[8].Name); |
404 | |
405 | ASSERT_FALSE(Macros[9].isDefinition()); |
406 | ASSERT_EQ("M", Macros[9].Name); |
407 | |
408 | ASSERT_TRUE(Macros[10].isExpansion()); |
409 | ASSERT_EQ("INC2", Macros[10].Name); |
410 | |
411 | ASSERT_TRUE(Macros[11].isDefinition()); |
412 | ASSERT_EQ("MACRO_IN_INCLUDE", Macros[11].Name); |
413 | |
414 | |
415 | |
416 | EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[3].Loc, Macros[4].Loc)); |
417 | |
418 | |
419 | |
420 | EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[10].Loc, Macros[11].Loc)); |
421 | } |
422 | |
423 | #endif |
424 | |
425 | } |
426 | |