|
20 | 20 | #include "clang/Lex/PreprocessorOptions.h"
|
21 | 21 | #include "llvm/ADT/SmallString.h"
|
22 | 22 | #include "llvm/Config/llvm-config.h"
|
| 23 | +#include "llvm/Support/MemoryBuffer.h" |
23 | 24 | #include "llvm/Support/Process.h"
|
24 | 25 | #include "gtest/gtest.h"
|
25 | 26 | #include <cstddef>
|
@@ -453,6 +454,65 @@ TEST_F(SourceManagerTest, loadedSLocEntryIsInTheSameTranslationUnit) {
|
453 | 454 |
|
454 | 455 | #if defined(LLVM_ON_UNIX)
|
455 | 456 |
|
| 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()); |
| 474 | + }; |
| 475 | + |
| 476 | + auto Buf = llvm::MemoryBuffer::getMemBuffer(""); |
| 477 | + FileEntryRef HeaderFile = |
| 478 | + FileMgr.getVirtualFileRef("/foo.h", Buf->getBufferSize(), 0); |
| 479 | + SourceMgr.overrideFileContents(HeaderFile, std::move(Buf)); |
| 480 | + |
| 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); |
| 486 | + |
| 487 | + Buf = llvm::MemoryBuffer::getMemBuffer(R"cpp(#include "/foo.h")cpp"); |
| 488 | + FileID MFID = SourceMgr.createFileID(std::move(Buf)); |
| 489 | + SourceMgr.setMainFileID(MFID); |
| 490 | + |
| 491 | + ParseFile(); |
| 492 | + auto FooFID = SourceMgr.getOrCreateFileID(HeaderFile, clang::SrcMgr::C_User); |
| 493 | + auto IncFID = SourceMgr.getDecomposedIncludedLoc(FooFID).first; |
| 494 | + EXPECT_EQ(IncFID, MFID); |
| 495 | + |
| 496 | + // Clean up source-manager state before we start next parse. |
| 497 | + SourceMgr.clearIDTables(); |
| 498 | + |
| 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); |
| 505 | + |
| 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); |
| 514 | +} |
| 515 | + |
456 | 516 | TEST_F(SourceManagerTest, getMacroArgExpandedLocation) {
|
457 | 517 | const char *header =
|
458 | 518 | "#define FM(x,y) x\n";
|
|
0 commit comments