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 //===----------------------------------------------------------------------===// 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 28 using namespace clang; 29 30 namespace clang { 31 class SourceManagerTestHelper { 32 public: 33 static FileID makeFileID(int ID) { return FileID::get(ID); } 34 }; 35 } // namespace clang 36 37 namespace { 38 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); 50 } 51 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; 60 }; 61 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); 70 71 EXPECT_FALSE(isWrittenInBuiltInFileFalse); 72 EXPECT_FALSE(isWrittenInCommandLineFileFalse); 73 EXPECT_FALSE(isWrittenInScratchSpaceFalse); 74 75 // Check for valid source location per filename for each method 76 const char *Source = "int x"; 77 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); 90 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); 103 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); 116 117 EXPECT_TRUE(isWrittenInBuiltInFileTrue); 118 EXPECT_TRUE(isWrittenInCommandLineFileTrue); 119 EXPECT_TRUE(isWrittenInScratchSpaceTrue); 120 } 121 122 TEST_F(SourceManagerTest, isInSystemHeader) { 123 // Check for invalid source location 124 SourceLocation LocEmpty; 125 bool isInSystemHeaderFalse = SourceMgr.isInSystemHeader(LocEmpty); 126 ASSERT_FALSE(isInSystemHeaderFalse); 127 } 128 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); 137 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(); 147 148 std::vector<Token> toks; 149 PP.LexTokensUntilEOF(&toks); 150 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()); 156 157 SourceLocation lsqrLoc = toks[0].getLocation(); 158 SourceLocation idLoc = toks[1].getLocation(); 159 SourceLocation rsqrLoc = toks[2].getLocation(); 160 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()); 165 166 SmallString<32> str; 167 ASSERT_EQ("M", PP.getSpelling(macroExpStartLoc, str)); 168 ASSERT_EQ(")", PP.getSpelling(macroExpEndLoc, str)); 169 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)); 174 } 175 176 TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithTokenSplit) { 177 const char *main = R"cpp( 178 #define ID(X) X 179 ID( 180 ID(a >> b) 181 c 182 ) 183 )cpp"; 184 185 SourceMgr.setMainFileID( 186 SourceMgr.createFileID(llvm::MemoryBuffer::getMemBuffer(main))); 187 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; 198 199 std::vector<Token> toks; 200 PP.LexTokensUntilEOF(&toks); 201 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())); 210 } 211 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); 226 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); 242 } 243 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Greater1, Greater2)); 244 EXPECT_FALSE(SourceMgr.isBeforeInTranslationUnit(Greater2, Greater1)); 245 } 246 247 TEST_F(SourceManagerTest, getColumnNumber) { 248 const char *Source = 249 "int x;\n" 250 "int y;"; 251 252 std::unique_ptr<llvm::MemoryBuffer> Buf = 253 llvm::MemoryBuffer::getMemBuffer(Source); 254 FileID MainFileID = SourceMgr.createFileID(std::move(Buf)); 255 SourceMgr.setMainFileID(MainFileID); 256 257 bool Invalid; 258 259 Invalid = false; 260 EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 0, &Invalid)); 261 EXPECT_TRUE(!Invalid); 262 263 Invalid = false; 264 EXPECT_EQ(5U, SourceMgr.getColumnNumber(MainFileID, 4, &Invalid)); 265 EXPECT_TRUE(!Invalid); 266 267 Invalid = false; 268 EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 7, &Invalid)); 269 EXPECT_TRUE(!Invalid); 270 271 Invalid = false; 272 EXPECT_EQ(5U, SourceMgr.getColumnNumber(MainFileID, 11, &Invalid)); 273 EXPECT_TRUE(!Invalid); 274 275 Invalid = false; 276 EXPECT_EQ(7U, SourceMgr.getColumnNumber(MainFileID, strlen(Source), 277 &Invalid)); 278 EXPECT_TRUE(!Invalid); 279 280 Invalid = false; 281 SourceMgr.getColumnNumber(MainFileID, strlen(Source)+1, &Invalid); 282 EXPECT_TRUE(Invalid); 283 284 // Test invalid files 285 Invalid = false; 286 SourceMgr.getColumnNumber(FileID(), 0, &Invalid); 287 EXPECT_TRUE(Invalid); 288 289 Invalid = false; 290 SourceMgr.getColumnNumber(FileID(), 1, &Invalid); 291 EXPECT_TRUE(Invalid); 292 293 // Test with no invalid flag. 294 EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 0, nullptr)); 295 } 296 297 TEST_F(SourceManagerTest, locationPrintTest) { 298 const char *header = "#define IDENTITY(x) x\n"; 299 300 const char *Source = "int x;\n" 301 "include \"test-header.h\"\n" 302 "IDENTITY(int y);\n" 303 "int z;"; 304 305 std::unique_ptr<llvm::MemoryBuffer> HeaderBuf = 306 llvm::MemoryBuffer::getMemBuffer(header); 307 std::unique_ptr<llvm::MemoryBuffer> Buf = 308 llvm::MemoryBuffer::getMemBuffer(Source); 309 310 FileEntryRef SourceFile = 311 FileMgr.getVirtualFileRef("/mainFile.cpp", Buf->getBufferSize(), 0); 312 SourceMgr.overrideFileContents(SourceFile, std::move(Buf)); 313 314 FileEntryRef HeaderFile = FileMgr.getVirtualFileRef( 315 "/test-header.h", HeaderBuf->getBufferSize(), 0); 316 SourceMgr.overrideFileContents(HeaderFile, std::move(HeaderBuf)); 317 318 FileID MainFileID = SourceMgr.getOrCreateFileID(SourceFile, SrcMgr::C_User); 319 FileID HeaderFileID = SourceMgr.getOrCreateFileID(HeaderFile, SrcMgr::C_User); 320 SourceMgr.setMainFileID(MainFileID); 321 322 auto BeginLoc = SourceMgr.getLocForStartOfFile(MainFileID); 323 auto EndLoc = SourceMgr.getLocForEndOfFile(MainFileID); 324 325 auto BeginEOLLoc = SourceMgr.translateLineCol(MainFileID, 1, 7); 326 327 auto HeaderLoc = SourceMgr.getLocForStartOfFile(HeaderFileID); 328 329 EXPECT_EQ(BeginLoc.printToString(SourceMgr), "/mainFile.cpp:1:1"); 330 EXPECT_EQ(EndLoc.printToString(SourceMgr), "/mainFile.cpp:4:7"); 331 332 EXPECT_EQ(BeginEOLLoc.printToString(SourceMgr), "/mainFile.cpp:1:7"); 333 EXPECT_EQ(HeaderLoc.printToString(SourceMgr), "/test-header.h:1:1"); 334 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>"); 343 } 344 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); 351 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)"); 384 } 385 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'; 392 } 393 394 std::unique_ptr<llvm::MemoryBuffer> Buf = 395 llvm::MemoryBuffer::getMemBuffer( 396 llvm::MemoryBufferRef( 397 llvm::StringRef(source.get(), 3), "whatever" 398 ), 399 false 400 ); 401 402 FileID mainFileID = SourceMgr.createFileID(std::move(Buf)); 403 SourceMgr.setMainFileID(mainFileID); 404 405 ASSERT_NO_FATAL_FAILURE(SourceMgr.getLineNumber(mainFileID, 1, nullptr)); 406 } 407 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 {}; 413 } 414 }; 415 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)); 421 }; 422 423 FakeExternalSLocEntrySource ExternalSource; 424 SourceMgr.setExternalSLocEntrySource(&ExternalSource); 425 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); 432 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); 439 440 // Loaded vs local. 441 EXPECT_FALSE(InSameTU(-2, 1)); 442 443 // Loaded in the same allocation A. 444 EXPECT_TRUE(InSameTU(-11, -2)); 445 EXPECT_TRUE(InSameTU(-11, -6)); 446 447 // Loaded in the same allocation B. 448 EXPECT_TRUE(InSameTU(-31, -12)); 449 EXPECT_TRUE(InSameTU(-31, -16)); 450 451 // Loaded from different allocations A and B. 452 EXPECT_FALSE(InSameTU(-12, -11)); 453 } 454 455 #if defined(LLVM_ON_UNIX) 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 516 TEST_F(SourceManagerTest, getMacroArgExpandedLocation) { 517 const char *header = 518 "#define FM(x,y) x\n"; 519 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"; 528 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); 535 536 FileEntryRef headerFile = FileMgr.getVirtualFileRef( 537 "/test-header.h", HeaderBuf->getBufferSize(), 0); 538 SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf)); 539 540 TrivialModuleLoader ModLoader; 541 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr, 542 Diags, LangOpts, &*Target); 543 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(); 555 556 std::vector<Token> toks; 557 PP.LexTokensUntilEOF(&toks); 558 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()); 565 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); 576 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()); 584 } 585 586 namespace { 587 588 struct MacroAction { 589 enum Kind { kExpansion, kDefinition, kUnDefinition}; 590 591 SourceLocation Loc; 592 std::string Name; 593 LLVM_PREFERRED_TYPE(Kind) 594 unsigned MAKind : 3; 595 596 MacroAction(SourceLocation Loc, StringRef Name, unsigned K) 597 : Loc(Loc), Name(std::string(Name)), MAKind(K) {} 598 599 bool isExpansion() const { return MAKind == kExpansion; } 600 bool isDefinition() const { return MAKind & kDefinition; } 601 bool isUnDefinition() const { return MAKind & kUnDefinition; } 602 }; 603 604 class MacroTracker : public PPCallbacks { 605 std::vector<MacroAction> &Macros; 606 607 public: 608 explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) { } 609 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)); 615 } 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)); 624 } 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)); 630 } 631 }; 632 633 } 634 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"; 641 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"; 648 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))); 654 655 FileEntryRef headerFile = FileMgr.getVirtualFileRef( 656 "/test-header.h", HeaderBuf->getBufferSize(), 0); 657 SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf)); 658 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); 667 668 std::vector<MacroAction> Macros; 669 PP.addPPCallbacks(std::make_unique<MacroTracker>(Macros)); 670 671 PP.EnterMainSourceFile(); 672 673 std::vector<Token> toks; 674 PP.LexTokensUntilEOF(&toks); 675 676 // Make sure we got the tokens that we expected. 677 ASSERT_EQ(0U, toks.size()); 678 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); 719 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)); 723 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)); 727 } 728 729 TEST_F(SourceManagerTest, isMainFile) { 730 const char *Source = "int x;"; 731 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)); 737 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)); 743 744 FileID MainFileID = SourceMgr.getOrCreateFileID(SourceFile, SrcMgr::C_User); 745 SourceMgr.setMainFileID(MainFileID); 746 747 EXPECT_TRUE(SourceMgr.isMainFile(*SourceFile)); 748 EXPECT_TRUE(SourceMgr.isMainFile(*SourceFile)); 749 EXPECT_FALSE(SourceMgr.isMainFile(*SecondFile)); 750 } 751 752 #endif 753 754 } // anonymous namespace 755