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