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