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