Reapply "[lldb][dwarf] Compute fully qualified names on simplified template names...
[llvm-project.git] / clang / unittests / Basic / SourceManagerTest.cpp
blob2b3fce9128ba9956dc2eb8a465e449ce829278e1
1 //===- unittests/Basic/SourceManagerTest.cpp ------ SourceManager tests ---===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
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 "llvm/Support/MemoryBuffer.h"
24 #include "llvm/Support/Process.h"
25 #include "gtest/gtest.h"
26 #include <cstddef>
28 using namespace clang;
30 namespace clang {
31 class SourceManagerTestHelper {
32 public:
33 static FileID makeFileID(int ID) { return FileID::get(ID); }
35 } // namespace clang
37 namespace {
39 // The test fixture.
40 class SourceManagerTest : public ::testing::Test {
41 protected:
42 SourceManagerTest()
43 : FileMgr(FileMgrOpts),
44 DiagID(new DiagnosticIDs()),
45 Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
46 SourceMgr(Diags, FileMgr),
47 TargetOpts(new TargetOptions) {
48 TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
49 Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
52 FileSystemOptions FileMgrOpts;
53 FileManager FileMgr;
54 IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
55 DiagnosticsEngine Diags;
56 SourceManager SourceMgr;
57 LangOptions LangOpts;
58 std::shared_ptr<TargetOptions> TargetOpts;
59 IntrusiveRefCntPtr<TargetInfo> Target;
62 TEST_F(SourceManagerTest, isInMemoryBuffersNoSourceLocationInfo) {
63 // Check for invalid source location for each method
64 SourceLocation LocEmpty;
65 bool isWrittenInBuiltInFileFalse = SourceMgr.isWrittenInBuiltinFile(LocEmpty);
66 bool isWrittenInCommandLineFileFalse =
67 SourceMgr.isWrittenInCommandLineFile(LocEmpty);
68 bool isWrittenInScratchSpaceFalse =
69 SourceMgr.isWrittenInScratchSpace(LocEmpty);
71 EXPECT_FALSE(isWrittenInBuiltInFileFalse);
72 EXPECT_FALSE(isWrittenInCommandLineFileFalse);
73 EXPECT_FALSE(isWrittenInScratchSpaceFalse);
75 // Check for valid source location per filename for each method
76 const char *Source = "int x";
78 std::unique_ptr<llvm::MemoryBuffer> BuiltInBuf =
79 llvm::MemoryBuffer::getMemBuffer(Source);
80 FileEntryRef BuiltInFile =
81 FileMgr.getVirtualFileRef("<built-in>", BuiltInBuf->getBufferSize(), 0);
82 SourceMgr.overrideFileContents(BuiltInFile, std::move(BuiltInBuf));
83 FileID BuiltInFileID =
84 SourceMgr.getOrCreateFileID(BuiltInFile, SrcMgr::C_User);
85 SourceMgr.setMainFileID(BuiltInFileID);
86 SourceLocation LocBuiltIn =
87 SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
88 bool isWrittenInBuiltInFileTrue =
89 SourceMgr.isWrittenInBuiltinFile(LocBuiltIn);
91 std::unique_ptr<llvm::MemoryBuffer> CommandLineBuf =
92 llvm::MemoryBuffer::getMemBuffer(Source);
93 FileEntryRef CommandLineFile = FileMgr.getVirtualFileRef(
94 "<command line>", CommandLineBuf->getBufferSize(), 0);
95 SourceMgr.overrideFileContents(CommandLineFile, std::move(CommandLineBuf));
96 FileID CommandLineFileID =
97 SourceMgr.getOrCreateFileID(CommandLineFile, SrcMgr::C_User);
98 SourceMgr.setMainFileID(CommandLineFileID);
99 SourceLocation LocCommandLine =
100 SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
101 bool isWrittenInCommandLineFileTrue =
102 SourceMgr.isWrittenInCommandLineFile(LocCommandLine);
104 std::unique_ptr<llvm::MemoryBuffer> ScratchSpaceBuf =
105 llvm::MemoryBuffer::getMemBuffer(Source);
106 FileEntryRef ScratchSpaceFile = FileMgr.getVirtualFileRef(
107 "<scratch space>", ScratchSpaceBuf->getBufferSize(), 0);
108 SourceMgr.overrideFileContents(ScratchSpaceFile, std::move(ScratchSpaceBuf));
109 FileID ScratchSpaceFileID =
110 SourceMgr.getOrCreateFileID(ScratchSpaceFile, SrcMgr::C_User);
111 SourceMgr.setMainFileID(ScratchSpaceFileID);
112 SourceLocation LocScratchSpace =
113 SourceMgr.getLocForStartOfFile(SourceMgr.getMainFileID());
114 bool isWrittenInScratchSpaceTrue =
115 SourceMgr.isWrittenInScratchSpace(LocScratchSpace);
117 EXPECT_TRUE(isWrittenInBuiltInFileTrue);
118 EXPECT_TRUE(isWrittenInCommandLineFileTrue);
119 EXPECT_TRUE(isWrittenInScratchSpaceTrue);
122 TEST_F(SourceManagerTest, isInSystemHeader) {
123 // Check for invalid source location
124 SourceLocation LocEmpty;
125 bool isInSystemHeaderFalse = SourceMgr.isInSystemHeader(LocEmpty);
126 ASSERT_FALSE(isInSystemHeaderFalse);
129 TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
130 const char *source =
131 "#define M(x) [x]\n"
132 "M(foo)";
133 std::unique_ptr<llvm::MemoryBuffer> Buf =
134 llvm::MemoryBuffer::getMemBuffer(source);
135 FileID mainFileID = SourceMgr.createFileID(std::move(Buf));
136 SourceMgr.setMainFileID(mainFileID);
138 TrivialModuleLoader ModLoader;
139 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
140 Diags, LangOpts, &*Target);
141 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
142 SourceMgr, HeaderInfo, ModLoader,
143 /*IILookup =*/nullptr,
144 /*OwnsHeaderSearch =*/false);
145 PP.Initialize(*Target);
146 PP.EnterMainSourceFile();
148 std::vector<Token> toks;
149 PP.LexTokensUntilEOF(&toks);
151 // Make sure we got the tokens that we expected.
152 ASSERT_EQ(3U, toks.size());
153 ASSERT_EQ(tok::l_square, toks[0].getKind());
154 ASSERT_EQ(tok::identifier, toks[1].getKind());
155 ASSERT_EQ(tok::r_square, toks[2].getKind());
157 SourceLocation lsqrLoc = toks[0].getLocation();
158 SourceLocation idLoc = toks[1].getLocation();
159 SourceLocation rsqrLoc = toks[2].getLocation();
161 SourceLocation macroExpStartLoc = SourceMgr.translateLineCol(mainFileID, 2, 1);
162 SourceLocation macroExpEndLoc = SourceMgr.translateLineCol(mainFileID, 2, 6);
163 ASSERT_TRUE(macroExpStartLoc.isFileID());
164 ASSERT_TRUE(macroExpEndLoc.isFileID());
166 SmallString<32> str;
167 ASSERT_EQ("M", PP.getSpelling(macroExpStartLoc, str));
168 ASSERT_EQ(")", PP.getSpelling(macroExpEndLoc, str));
170 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(lsqrLoc, idLoc));
171 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, rsqrLoc));
172 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(macroExpStartLoc, idLoc));
173 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, macroExpEndLoc));
176 TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithTokenSplit) {
177 const char *main = R"cpp(
178 #define ID(X) X
180 ID(a >> b)
183 )cpp";
185 SourceMgr.setMainFileID(
186 SourceMgr.createFileID(llvm::MemoryBuffer::getMemBuffer(main)));
188 TrivialModuleLoader ModLoader;
189 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
190 Diags, LangOpts, &*Target);
191 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
192 SourceMgr, HeaderInfo, ModLoader,
193 /*IILookup =*/nullptr,
194 /*OwnsHeaderSearch =*/false);
195 PP.Initialize(*Target);
196 PP.EnterMainSourceFile();
197 llvm::SmallString<8> Scratch;
199 std::vector<Token> toks;
200 PP.LexTokensUntilEOF(&toks);
202 // Make sure we got the tokens that we expected.
203 ASSERT_EQ(4U, toks.size()) << "a >> b c";
204 // Sanity check their order.
205 for (unsigned I = 0; I < toks.size() - 1; ++I) {
206 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(toks[I].getLocation(),
207 toks[I + 1].getLocation()));
208 EXPECT_FALSE(SourceMgr.isBeforeInTranslationUnit(toks[I + 1].getLocation(),
209 toks[I].getLocation()));
212 // Split the >> into two > tokens, as happens when parsing nested templates.
213 unsigned RightShiftIndex = 1;
214 SourceLocation RightShift = toks[RightShiftIndex].getLocation();
215 EXPECT_EQ(">>", Lexer::getSpelling(SourceMgr.getSpellingLoc(RightShift),
216 Scratch, SourceMgr, LangOpts));
217 SourceLocation Greater1 = PP.SplitToken(RightShift, /*Length=*/1);
218 SourceLocation Greater2 = RightShift.getLocWithOffset(1);
219 EXPECT_TRUE(Greater1.isMacroID());
220 EXPECT_EQ(">", Lexer::getSpelling(SourceMgr.getSpellingLoc(Greater1), Scratch,
221 SourceMgr, LangOpts));
222 EXPECT_EQ(">", Lexer::getSpelling(SourceMgr.getSpellingLoc(Greater2), Scratch,
223 SourceMgr, LangOpts));
224 EXPECT_EQ(SourceMgr.getImmediateExpansionRange(Greater1).getBegin(),
225 RightShift);
227 for (unsigned I = 0; I < toks.size(); ++I) {
228 SCOPED_TRACE("Token " + std::to_string(I));
229 // Right-shift is the parent of Greater1, so it compares less.
230 EXPECT_EQ(
231 SourceMgr.isBeforeInTranslationUnit(toks[I].getLocation(), Greater1),
232 I <= RightShiftIndex);
233 EXPECT_EQ(
234 SourceMgr.isBeforeInTranslationUnit(toks[I].getLocation(), Greater2),
235 I <= RightShiftIndex);
236 EXPECT_EQ(
237 SourceMgr.isBeforeInTranslationUnit(Greater1, toks[I].getLocation()),
238 RightShiftIndex < I);
239 EXPECT_EQ(
240 SourceMgr.isBeforeInTranslationUnit(Greater2, toks[I].getLocation()),
241 RightShiftIndex < I);
243 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Greater1, Greater2));
244 EXPECT_FALSE(SourceMgr.isBeforeInTranslationUnit(Greater2, Greater1));
247 TEST_F(SourceManagerTest, getColumnNumber) {
248 const char *Source =
249 "int x;\n"
250 "int y;";
252 std::unique_ptr<llvm::MemoryBuffer> Buf =
253 llvm::MemoryBuffer::getMemBuffer(Source);
254 FileID MainFileID = SourceMgr.createFileID(std::move(Buf));
255 SourceMgr.setMainFileID(MainFileID);
257 bool Invalid;
259 Invalid = false;
260 EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 0, &Invalid));
261 EXPECT_TRUE(!Invalid);
263 Invalid = false;
264 EXPECT_EQ(5U, SourceMgr.getColumnNumber(MainFileID, 4, &Invalid));
265 EXPECT_TRUE(!Invalid);
267 Invalid = false;
268 EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 7, &Invalid));
269 EXPECT_TRUE(!Invalid);
271 Invalid = false;
272 EXPECT_EQ(5U, SourceMgr.getColumnNumber(MainFileID, 11, &Invalid));
273 EXPECT_TRUE(!Invalid);
275 Invalid = false;
276 EXPECT_EQ(7U, SourceMgr.getColumnNumber(MainFileID, strlen(Source),
277 &Invalid));
278 EXPECT_TRUE(!Invalid);
280 Invalid = false;
281 SourceMgr.getColumnNumber(MainFileID, strlen(Source)+1, &Invalid);
282 EXPECT_TRUE(Invalid);
284 // Test invalid files
285 Invalid = false;
286 SourceMgr.getColumnNumber(FileID(), 0, &Invalid);
287 EXPECT_TRUE(Invalid);
289 Invalid = false;
290 SourceMgr.getColumnNumber(FileID(), 1, &Invalid);
291 EXPECT_TRUE(Invalid);
293 // Test with no invalid flag.
294 EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 0, nullptr));
297 TEST_F(SourceManagerTest, locationPrintTest) {
298 const char *header = "#define IDENTITY(x) x\n";
300 const char *Source = "int x;\n"
301 "include \"test-header.h\"\n"
302 "IDENTITY(int y);\n"
303 "int z;";
305 std::unique_ptr<llvm::MemoryBuffer> HeaderBuf =
306 llvm::MemoryBuffer::getMemBuffer(header);
307 std::unique_ptr<llvm::MemoryBuffer> Buf =
308 llvm::MemoryBuffer::getMemBuffer(Source);
310 FileEntryRef SourceFile =
311 FileMgr.getVirtualFileRef("/mainFile.cpp", Buf->getBufferSize(), 0);
312 SourceMgr.overrideFileContents(SourceFile, std::move(Buf));
314 FileEntryRef HeaderFile = FileMgr.getVirtualFileRef(
315 "/test-header.h", HeaderBuf->getBufferSize(), 0);
316 SourceMgr.overrideFileContents(HeaderFile, std::move(HeaderBuf));
318 FileID MainFileID = SourceMgr.getOrCreateFileID(SourceFile, SrcMgr::C_User);
319 FileID HeaderFileID = SourceMgr.getOrCreateFileID(HeaderFile, SrcMgr::C_User);
320 SourceMgr.setMainFileID(MainFileID);
322 auto BeginLoc = SourceMgr.getLocForStartOfFile(MainFileID);
323 auto EndLoc = SourceMgr.getLocForEndOfFile(MainFileID);
325 auto BeginEOLLoc = SourceMgr.translateLineCol(MainFileID, 1, 7);
327 auto HeaderLoc = SourceMgr.getLocForStartOfFile(HeaderFileID);
329 EXPECT_EQ(BeginLoc.printToString(SourceMgr), "/mainFile.cpp:1:1");
330 EXPECT_EQ(EndLoc.printToString(SourceMgr), "/mainFile.cpp:4:7");
332 EXPECT_EQ(BeginEOLLoc.printToString(SourceMgr), "/mainFile.cpp:1:7");
333 EXPECT_EQ(HeaderLoc.printToString(SourceMgr), "/test-header.h:1:1");
335 EXPECT_EQ(SourceRange(BeginLoc, BeginLoc).printToString(SourceMgr),
336 "</mainFile.cpp:1:1>");
337 EXPECT_EQ(SourceRange(BeginLoc, BeginEOLLoc).printToString(SourceMgr),
338 "</mainFile.cpp:1:1, col:7>");
339 EXPECT_EQ(SourceRange(BeginLoc, EndLoc).printToString(SourceMgr),
340 "</mainFile.cpp:1:1, line:4:7>");
341 EXPECT_EQ(SourceRange(BeginLoc, HeaderLoc).printToString(SourceMgr),
342 "</mainFile.cpp:1:1, /test-header.h:1:1>");
345 TEST_F(SourceManagerTest, getInvalidBOM) {
346 ASSERT_EQ(SrcMgr::ContentCache::getInvalidBOM(""), nullptr);
347 ASSERT_EQ(SrcMgr::ContentCache::getInvalidBOM("\x00\x00\x00"), nullptr);
348 ASSERT_EQ(SrcMgr::ContentCache::getInvalidBOM("\xFF\xFF\xFF"), nullptr);
349 ASSERT_EQ(SrcMgr::ContentCache::getInvalidBOM("#include <iostream>"),
350 nullptr);
352 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM(
353 "\xFE\xFF#include <iostream>")),
354 "UTF-16 (BE)");
355 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM(
356 "\xFF\xFE#include <iostream>")),
357 "UTF-16 (LE)");
358 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM(
359 "\x2B\x2F\x76#include <iostream>")),
360 "UTF-7");
361 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM(
362 "\xF7\x64\x4C#include <iostream>")),
363 "UTF-1");
364 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM(
365 "\xDD\x73\x66\x73#include <iostream>")),
366 "UTF-EBCDIC");
367 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM(
368 "\x0E\xFE\xFF#include <iostream>")),
369 "SCSU");
370 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM(
371 "\xFB\xEE\x28#include <iostream>")),
372 "BOCU-1");
373 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM(
374 "\x84\x31\x95\x33#include <iostream>")),
375 "GB-18030");
376 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM(
377 llvm::StringLiteral::withInnerNUL(
378 "\x00\x00\xFE\xFF#include <iostream>"))),
379 "UTF-32 (BE)");
380 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM(
381 llvm::StringLiteral::withInnerNUL(
382 "\xFF\xFE\x00\x00#include <iostream>"))),
383 "UTF-32 (LE)");
386 // Regression test - there was an out of bound access for buffers not terminated by zero.
387 TEST_F(SourceManagerTest, getLineNumber) {
388 const unsigned pageSize = llvm::sys::Process::getPageSizeEstimate();
389 std::unique_ptr<char[]> source(new char[pageSize]);
390 for(unsigned i = 0; i < pageSize; ++i) {
391 source[i] = 'a';
394 std::unique_ptr<llvm::MemoryBuffer> Buf =
395 llvm::MemoryBuffer::getMemBuffer(
396 llvm::MemoryBufferRef(
397 llvm::StringRef(source.get(), 3), "whatever"
399 false
402 FileID mainFileID = SourceMgr.createFileID(std::move(Buf));
403 SourceMgr.setMainFileID(mainFileID);
405 ASSERT_NO_FATAL_FAILURE(SourceMgr.getLineNumber(mainFileID, 1, nullptr));
408 struct FakeExternalSLocEntrySource : ExternalSLocEntrySource {
409 bool ReadSLocEntry(int ID) override { return {}; }
410 int getSLocEntryID(SourceLocation::UIntTy SLocOffset) override { return 0; }
411 std::pair<SourceLocation, StringRef> getModuleImportLoc(int ID) override {
412 return {};
416 TEST_F(SourceManagerTest, loadedSLocEntryIsInTheSameTranslationUnit) {
417 auto InSameTU = [=](int LID, int RID) {
418 return SourceMgr.isInTheSameTranslationUnitImpl(
419 std::make_pair(SourceManagerTestHelper::makeFileID(LID), 0),
420 std::make_pair(SourceManagerTestHelper::makeFileID(RID), 0));
423 FakeExternalSLocEntrySource ExternalSource;
424 SourceMgr.setExternalSLocEntrySource(&ExternalSource);
426 unsigned ANumFileIDs = 10;
427 auto [AFirstID, X] = SourceMgr.AllocateLoadedSLocEntries(ANumFileIDs, 10);
428 int ALastID = AFirstID + ANumFileIDs - 1;
429 // FileID(-11)..FileID(-2)
430 ASSERT_EQ(AFirstID, -11);
431 ASSERT_EQ(ALastID, -2);
433 unsigned BNumFileIDs = 20;
434 auto [BFirstID, Y] = SourceMgr.AllocateLoadedSLocEntries(BNumFileIDs, 20);
435 int BLastID = BFirstID + BNumFileIDs - 1;
436 // FileID(-31)..FileID(-12)
437 ASSERT_EQ(BFirstID, -31);
438 ASSERT_EQ(BLastID, -12);
440 // Loaded vs local.
441 EXPECT_FALSE(InSameTU(-2, 1));
443 // Loaded in the same allocation A.
444 EXPECT_TRUE(InSameTU(-11, -2));
445 EXPECT_TRUE(InSameTU(-11, -6));
447 // Loaded in the same allocation B.
448 EXPECT_TRUE(InSameTU(-31, -12));
449 EXPECT_TRUE(InSameTU(-31, -16));
451 // Loaded from different allocations A and B.
452 EXPECT_FALSE(InSameTU(-12, -11));
455 #if defined(LLVM_ON_UNIX)
457 // A single SourceManager instance is sometimes reused across multiple
458 // compilations. This test makes sure we're resetting caches built for tracking
459 // include locations that are based on FileIDs, to make sure we don't report
460 // wrong include locations when FileIDs coincide between two different runs.
461 TEST_F(SourceManagerTest, ResetsIncludeLocMap) {
462 auto ParseFile = [&] {
463 TrivialModuleLoader ModLoader;
464 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
465 Diags, LangOpts, &*Target);
466 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
467 SourceMgr, HeaderInfo, ModLoader,
468 /*IILookup =*/nullptr,
469 /*OwnsHeaderSearch =*/false);
470 PP.Initialize(*Target);
471 PP.EnterMainSourceFile();
472 PP.LexTokensUntilEOF();
473 EXPECT_FALSE(Diags.hasErrorOccurred());
476 auto Buf = llvm::MemoryBuffer::getMemBuffer("");
477 FileEntryRef HeaderFile =
478 FileMgr.getVirtualFileRef("/foo.h", Buf->getBufferSize(), 0);
479 SourceMgr.overrideFileContents(HeaderFile, std::move(Buf));
481 Buf = llvm::MemoryBuffer::getMemBuffer(R"cpp(#include "/foo.h")cpp");
482 FileEntryRef BarFile =
483 FileMgr.getVirtualFileRef("/bar.h", Buf->getBufferSize(), 0);
484 SourceMgr.overrideFileContents(BarFile, std::move(Buf));
485 SourceMgr.createFileID(BarFile, {}, clang::SrcMgr::C_User);
487 Buf = llvm::MemoryBuffer::getMemBuffer(R"cpp(#include "/foo.h")cpp");
488 FileID MFID = SourceMgr.createFileID(std::move(Buf));
489 SourceMgr.setMainFileID(MFID);
491 ParseFile();
492 auto FooFID = SourceMgr.getOrCreateFileID(HeaderFile, clang::SrcMgr::C_User);
493 auto IncFID = SourceMgr.getDecomposedIncludedLoc(FooFID).first;
494 EXPECT_EQ(IncFID, MFID);
496 // Clean up source-manager state before we start next parse.
497 SourceMgr.clearIDTables();
499 // Set up a new main file.
500 Buf = llvm::MemoryBuffer::getMemBuffer(R"cpp(
501 // silly comment 42
502 #include "/bar.h")cpp");
503 MFID = SourceMgr.createFileID(std::move(Buf));
504 SourceMgr.setMainFileID(MFID);
506 ParseFile();
507 // Make sure foo.h got the same file-id in both runs.
508 EXPECT_EQ(FooFID,
509 SourceMgr.getOrCreateFileID(HeaderFile, clang::SrcMgr::C_User));
510 auto BarFID = SourceMgr.getOrCreateFileID(BarFile, clang::SrcMgr::C_User);
511 IncFID = SourceMgr.getDecomposedIncludedLoc(FooFID).first;
512 // Check that includer is bar.h during this run.
513 EXPECT_EQ(IncFID, BarFID);
516 TEST_F(SourceManagerTest, getMacroArgExpandedLocation) {
517 const char *header =
518 "#define FM(x,y) x\n";
520 const char *main =
521 "#include \"/test-header.h\"\n"
522 "#define VAL 0\n"
523 "FM(VAL,0)\n"
524 "FM(0,VAL)\n"
525 "FM(FM(0,VAL),0)\n"
526 "#define CONCAT(X, Y) X##Y\n"
527 "CONCAT(1,1)\n";
529 std::unique_ptr<llvm::MemoryBuffer> HeaderBuf =
530 llvm::MemoryBuffer::getMemBuffer(header);
531 std::unique_ptr<llvm::MemoryBuffer> MainBuf =
532 llvm::MemoryBuffer::getMemBuffer(main);
533 FileID mainFileID = SourceMgr.createFileID(std::move(MainBuf));
534 SourceMgr.setMainFileID(mainFileID);
536 FileEntryRef headerFile = FileMgr.getVirtualFileRef(
537 "/test-header.h", HeaderBuf->getBufferSize(), 0);
538 SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf));
540 TrivialModuleLoader ModLoader;
541 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
542 Diags, LangOpts, &*Target);
544 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
545 SourceMgr, HeaderInfo, ModLoader,
546 /*IILookup =*/nullptr,
547 /*OwnsHeaderSearch =*/false);
548 // Ensure we can get expanded locations in presence of implicit includes.
549 // These are different than normal includes since predefines buffer doesn't
550 // have a valid insertion location.
551 PP.setPredefines("#include \"/implicit-header.h\"");
552 FileMgr.getVirtualFileRef("/implicit-header.h", 0, 0);
553 PP.Initialize(*Target);
554 PP.EnterMainSourceFile();
556 std::vector<Token> toks;
557 PP.LexTokensUntilEOF(&toks);
559 // Make sure we got the tokens that we expected.
560 ASSERT_EQ(4U, toks.size());
561 ASSERT_EQ(tok::numeric_constant, toks[0].getKind());
562 ASSERT_EQ(tok::numeric_constant, toks[1].getKind());
563 ASSERT_EQ(tok::numeric_constant, toks[2].getKind());
564 ASSERT_EQ(tok::numeric_constant, toks[3].getKind());
566 SourceLocation defLoc = SourceMgr.translateLineCol(mainFileID, 2, 13);
567 SourceLocation loc1 = SourceMgr.translateLineCol(mainFileID, 3, 8);
568 SourceLocation loc2 = SourceMgr.translateLineCol(mainFileID, 4, 4);
569 SourceLocation loc3 = SourceMgr.translateLineCol(mainFileID, 5, 7);
570 SourceLocation defLoc2 = SourceMgr.translateLineCol(mainFileID, 6, 22);
571 defLoc = SourceMgr.getMacroArgExpandedLocation(defLoc);
572 loc1 = SourceMgr.getMacroArgExpandedLocation(loc1);
573 loc2 = SourceMgr.getMacroArgExpandedLocation(loc2);
574 loc3 = SourceMgr.getMacroArgExpandedLocation(loc3);
575 defLoc2 = SourceMgr.getMacroArgExpandedLocation(defLoc2);
577 EXPECT_TRUE(defLoc.isFileID());
578 EXPECT_TRUE(loc1.isFileID());
579 EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc2));
580 EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc3));
581 EXPECT_EQ(loc2, toks[1].getLocation());
582 EXPECT_EQ(loc3, toks[2].getLocation());
583 EXPECT_TRUE(defLoc2.isFileID());
586 namespace {
588 struct MacroAction {
589 enum Kind { kExpansion, kDefinition, kUnDefinition};
591 SourceLocation Loc;
592 std::string Name;
593 LLVM_PREFERRED_TYPE(Kind)
594 unsigned MAKind : 3;
596 MacroAction(SourceLocation Loc, StringRef Name, unsigned K)
597 : Loc(Loc), Name(std::string(Name)), MAKind(K) {}
599 bool isExpansion() const { return MAKind == kExpansion; }
600 bool isDefinition() const { return MAKind & kDefinition; }
601 bool isUnDefinition() const { return MAKind & kUnDefinition; }
604 class MacroTracker : public PPCallbacks {
605 std::vector<MacroAction> &Macros;
607 public:
608 explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) { }
610 void MacroDefined(const Token &MacroNameTok,
611 const MacroDirective *MD) override {
612 Macros.push_back(MacroAction(MD->getLocation(),
613 MacroNameTok.getIdentifierInfo()->getName(),
614 MacroAction::kDefinition));
616 void MacroUndefined(const Token &MacroNameTok,
617 const MacroDefinition &MD,
618 const MacroDirective *UD) override {
619 Macros.push_back(
620 MacroAction(UD ? UD->getLocation() : SourceLocation(),
621 MacroNameTok.getIdentifierInfo()->getName(),
622 UD ? MacroAction::kDefinition | MacroAction::kUnDefinition
623 : MacroAction::kUnDefinition));
625 void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
626 SourceRange Range, const MacroArgs *Args) override {
627 Macros.push_back(MacroAction(MacroNameTok.getLocation(),
628 MacroNameTok.getIdentifierInfo()->getName(),
629 MacroAction::kExpansion));
635 TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
636 const char *header =
637 "#define MACRO_IN_INCLUDE 0\n"
638 "#define MACRO_DEFINED\n"
639 "#undef MACRO_DEFINED\n"
640 "#undef MACRO_UNDEFINED\n";
642 const char *main =
643 "#define M(x) x\n"
644 "#define INC \"/test-header.h\"\n"
645 "#include M(INC)\n"
646 "#define INC2 </test-header.h>\n"
647 "#include M(INC2)\n";
649 std::unique_ptr<llvm::MemoryBuffer> HeaderBuf =
650 llvm::MemoryBuffer::getMemBuffer(header);
651 std::unique_ptr<llvm::MemoryBuffer> MainBuf =
652 llvm::MemoryBuffer::getMemBuffer(main);
653 SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(MainBuf)));
655 FileEntryRef headerFile = FileMgr.getVirtualFileRef(
656 "/test-header.h", HeaderBuf->getBufferSize(), 0);
657 SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf));
659 TrivialModuleLoader ModLoader;
660 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
661 Diags, LangOpts, &*Target);
662 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
663 SourceMgr, HeaderInfo, ModLoader,
664 /*IILookup =*/nullptr,
665 /*OwnsHeaderSearch =*/false);
666 PP.Initialize(*Target);
668 std::vector<MacroAction> Macros;
669 PP.addPPCallbacks(std::make_unique<MacroTracker>(Macros));
671 PP.EnterMainSourceFile();
673 std::vector<Token> toks;
674 PP.LexTokensUntilEOF(&toks);
676 // Make sure we got the tokens that we expected.
677 ASSERT_EQ(0U, toks.size());
679 ASSERT_EQ(15U, Macros.size());
680 // #define M(x) x
681 ASSERT_TRUE(Macros[0].isDefinition());
682 ASSERT_EQ("M", Macros[0].Name);
683 // #define INC "/test-header.h"
684 ASSERT_TRUE(Macros[1].isDefinition());
685 ASSERT_EQ("INC", Macros[1].Name);
686 // M expansion in #include M(INC)
687 ASSERT_FALSE(Macros[2].isDefinition());
688 ASSERT_EQ("M", Macros[2].Name);
689 // INC expansion in #include M(INC)
690 ASSERT_TRUE(Macros[3].isExpansion());
691 ASSERT_EQ("INC", Macros[3].Name);
692 // #define MACRO_IN_INCLUDE 0
693 ASSERT_TRUE(Macros[4].isDefinition());
694 ASSERT_EQ("MACRO_IN_INCLUDE", Macros[4].Name);
695 // #define MACRO_DEFINED
696 ASSERT_TRUE(Macros[5].isDefinition());
697 ASSERT_FALSE(Macros[5].isUnDefinition());
698 ASSERT_EQ("MACRO_DEFINED", Macros[5].Name);
699 // #undef MACRO_DEFINED
700 ASSERT_TRUE(Macros[6].isDefinition());
701 ASSERT_TRUE(Macros[6].isUnDefinition());
702 ASSERT_EQ("MACRO_DEFINED", Macros[6].Name);
703 // #undef MACRO_UNDEFINED
704 ASSERT_FALSE(Macros[7].isDefinition());
705 ASSERT_TRUE(Macros[7].isUnDefinition());
706 ASSERT_EQ("MACRO_UNDEFINED", Macros[7].Name);
707 // #define INC2 </test-header.h>
708 ASSERT_TRUE(Macros[8].isDefinition());
709 ASSERT_EQ("INC2", Macros[8].Name);
710 // M expansion in #include M(INC2)
711 ASSERT_FALSE(Macros[9].isDefinition());
712 ASSERT_EQ("M", Macros[9].Name);
713 // INC2 expansion in #include M(INC2)
714 ASSERT_TRUE(Macros[10].isExpansion());
715 ASSERT_EQ("INC2", Macros[10].Name);
716 // #define MACRO_IN_INCLUDE 0
717 ASSERT_TRUE(Macros[11].isDefinition());
718 ASSERT_EQ("MACRO_IN_INCLUDE", Macros[11].Name);
720 // The INC expansion in #include M(INC) comes before the first
721 // MACRO_IN_INCLUDE definition of the included file.
722 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[3].Loc, Macros[4].Loc));
724 // The INC2 expansion in #include M(INC2) comes before the second
725 // MACRO_IN_INCLUDE definition of the included file.
726 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[10].Loc, Macros[11].Loc));
729 TEST_F(SourceManagerTest, isMainFile) {
730 const char *Source = "int x;";
732 std::unique_ptr<llvm::MemoryBuffer> Buf =
733 llvm::MemoryBuffer::getMemBuffer(Source);
734 FileEntryRef SourceFile =
735 FileMgr.getVirtualFileRef("mainFile.cpp", Buf->getBufferSize(), 0);
736 SourceMgr.overrideFileContents(SourceFile, std::move(Buf));
738 std::unique_ptr<llvm::MemoryBuffer> Buf2 =
739 llvm::MemoryBuffer::getMemBuffer(Source);
740 FileEntryRef SecondFile =
741 FileMgr.getVirtualFileRef("file2.cpp", Buf2->getBufferSize(), 0);
742 SourceMgr.overrideFileContents(SecondFile, std::move(Buf2));
744 FileID MainFileID = SourceMgr.getOrCreateFileID(SourceFile, SrcMgr::C_User);
745 SourceMgr.setMainFileID(MainFileID);
747 EXPECT_TRUE(SourceMgr.isMainFile(*SourceFile));
748 EXPECT_TRUE(SourceMgr.isMainFile(*SourceFile));
749 EXPECT_FALSE(SourceMgr.isMainFile(*SecondFile));
752 #endif
754 } // anonymous namespace