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 "gtest/gtest.h" 24 25 using namespace clang; 26 27 namespace { 28 29 // The test fixture. 30 class SourceManagerTest : public ::testing::Test { 31 protected: 32 SourceManagerTest() 33 : FileMgr(FileMgrOpts), 34 DiagID(new DiagnosticIDs()), 35 Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()), 36 SourceMgr(Diags, FileMgr), 37 TargetOpts(new TargetOptions) { 38 TargetOpts->Triple = "x86_64-apple-darwin11.1.0"; 39 Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts); 40 } 41 42 FileSystemOptions FileMgrOpts; 43 FileManager FileMgr; 44 IntrusiveRefCntPtr<DiagnosticIDs> DiagID; 45 DiagnosticsEngine Diags; 46 SourceManager SourceMgr; 47 LangOptions LangOpts; 48 std::shared_ptr<TargetOptions> TargetOpts; 49 IntrusiveRefCntPtr<TargetInfo> Target; 50 }; 51 52 TEST_F(SourceManagerTest, isBeforeInTranslationUnit) { 53 const char *source = 54 "#define M(x) [x]\n" 55 "M(foo)"; 56 std::unique_ptr<llvm::MemoryBuffer> Buf = 57 llvm::MemoryBuffer::getMemBuffer(source); 58 FileID mainFileID = SourceMgr.createFileID(std::move(Buf)); 59 SourceMgr.setMainFileID(mainFileID); 60 61 TrivialModuleLoader ModLoader; 62 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr, 63 Diags, LangOpts, &*Target); 64 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts, 65 SourceMgr, HeaderInfo, ModLoader, 66 /*IILookup =*/nullptr, 67 /*OwnsHeaderSearch =*/false); 68 PP.Initialize(*Target); 69 PP.EnterMainSourceFile(); 70 71 std::vector<Token> toks; 72 while (1) { 73 Token tok; 74 PP.Lex(tok); 75 if (tok.is(tok::eof)) 76 break; 77 toks.push_back(tok); 78 } 79 80 // Make sure we got the tokens that we expected. 81 ASSERT_EQ(3U, toks.size()); 82 ASSERT_EQ(tok::l_square, toks[0].getKind()); 83 ASSERT_EQ(tok::identifier, toks[1].getKind()); 84 ASSERT_EQ(tok::r_square, toks[2].getKind()); 85 86 SourceLocation lsqrLoc = toks[0].getLocation(); 87 SourceLocation idLoc = toks[1].getLocation(); 88 SourceLocation rsqrLoc = toks[2].getLocation(); 89 90 SourceLocation macroExpStartLoc = SourceMgr.translateLineCol(mainFileID, 2, 1); 91 SourceLocation macroExpEndLoc = SourceMgr.translateLineCol(mainFileID, 2, 6); 92 ASSERT_TRUE(macroExpStartLoc.isFileID()); 93 ASSERT_TRUE(macroExpEndLoc.isFileID()); 94 95 SmallString<32> str; 96 ASSERT_EQ("M", PP.getSpelling(macroExpStartLoc, str)); 97 ASSERT_EQ(")", PP.getSpelling(macroExpEndLoc, str)); 98 99 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(lsqrLoc, idLoc)); 100 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, rsqrLoc)); 101 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(macroExpStartLoc, idLoc)); 102 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, macroExpEndLoc)); 103 } 104 105 TEST_F(SourceManagerTest, getColumnNumber) { 106 const char *Source = 107 "int x;\n" 108 "int y;"; 109 110 std::unique_ptr<llvm::MemoryBuffer> Buf = 111 llvm::MemoryBuffer::getMemBuffer(Source); 112 FileID MainFileID = SourceMgr.createFileID(std::move(Buf)); 113 SourceMgr.setMainFileID(MainFileID); 114 115 bool Invalid; 116 117 Invalid = false; 118 EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 0, &Invalid)); 119 EXPECT_TRUE(!Invalid); 120 121 Invalid = false; 122 EXPECT_EQ(5U, SourceMgr.getColumnNumber(MainFileID, 4, &Invalid)); 123 EXPECT_TRUE(!Invalid); 124 125 Invalid = false; 126 EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 7, &Invalid)); 127 EXPECT_TRUE(!Invalid); 128 129 Invalid = false; 130 EXPECT_EQ(5U, SourceMgr.getColumnNumber(MainFileID, 11, &Invalid)); 131 EXPECT_TRUE(!Invalid); 132 133 Invalid = false; 134 EXPECT_EQ(7U, SourceMgr.getColumnNumber(MainFileID, strlen(Source), 135 &Invalid)); 136 EXPECT_TRUE(!Invalid); 137 138 Invalid = false; 139 SourceMgr.getColumnNumber(MainFileID, strlen(Source)+1, &Invalid); 140 EXPECT_TRUE(Invalid); 141 142 // Test invalid files 143 Invalid = false; 144 SourceMgr.getColumnNumber(FileID(), 0, &Invalid); 145 EXPECT_TRUE(Invalid); 146 147 Invalid = false; 148 SourceMgr.getColumnNumber(FileID(), 1, &Invalid); 149 EXPECT_TRUE(Invalid); 150 151 // Test with no invalid flag. 152 EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 0, nullptr)); 153 } 154 155 TEST_F(SourceManagerTest, locationPrintTest) { 156 const char *header = "#define IDENTITY(x) x\n"; 157 158 const char *Source = "int x;\n" 159 "include \"test-header.h\"\n" 160 "IDENTITY(int y);\n" 161 "int z;"; 162 163 std::unique_ptr<llvm::MemoryBuffer> HeaderBuf = 164 llvm::MemoryBuffer::getMemBuffer(header); 165 std::unique_ptr<llvm::MemoryBuffer> Buf = 166 llvm::MemoryBuffer::getMemBuffer(Source); 167 168 const FileEntry *SourceFile = 169 FileMgr.getVirtualFile("/mainFile.cpp", Buf->getBufferSize(), 0); 170 SourceMgr.overrideFileContents(SourceFile, std::move(Buf)); 171 172 const FileEntry *HeaderFile = 173 FileMgr.getVirtualFile("/test-header.h", HeaderBuf->getBufferSize(), 0); 174 SourceMgr.overrideFileContents(HeaderFile, std::move(HeaderBuf)); 175 176 FileID MainFileID = SourceMgr.getOrCreateFileID(SourceFile, SrcMgr::C_User); 177 FileID HeaderFileID = SourceMgr.getOrCreateFileID(HeaderFile, SrcMgr::C_User); 178 SourceMgr.setMainFileID(MainFileID); 179 180 auto BeginLoc = SourceMgr.getLocForStartOfFile(MainFileID); 181 auto EndLoc = SourceMgr.getLocForEndOfFile(MainFileID); 182 183 auto BeginEOLLoc = SourceMgr.translateLineCol(MainFileID, 1, 7); 184 185 auto HeaderLoc = SourceMgr.getLocForStartOfFile(HeaderFileID); 186 187 EXPECT_EQ(BeginLoc.printToString(SourceMgr), "/mainFile.cpp:1:1"); 188 EXPECT_EQ(EndLoc.printToString(SourceMgr), "/mainFile.cpp:4:7"); 189 190 EXPECT_EQ(BeginEOLLoc.printToString(SourceMgr), "/mainFile.cpp:1:7"); 191 EXPECT_EQ(HeaderLoc.printToString(SourceMgr), "/test-header.h:1:1"); 192 193 EXPECT_EQ(SourceRange(BeginLoc, BeginLoc).printToString(SourceMgr), 194 "</mainFile.cpp:1:1>"); 195 EXPECT_EQ(SourceRange(BeginLoc, BeginEOLLoc).printToString(SourceMgr), 196 "</mainFile.cpp:1:1, col:7>"); 197 EXPECT_EQ(SourceRange(BeginLoc, EndLoc).printToString(SourceMgr), 198 "</mainFile.cpp:1:1, line:4:7>"); 199 EXPECT_EQ(SourceRange(BeginLoc, HeaderLoc).printToString(SourceMgr), 200 "</mainFile.cpp:1:1, /test-header.h:1:1>"); 201 } 202 203 TEST_F(SourceManagerTest, getInvalidBOM) { 204 ASSERT_EQ(SrcMgr::ContentCache::getInvalidBOM(""), nullptr); 205 ASSERT_EQ(SrcMgr::ContentCache::getInvalidBOM("\x00\x00\x00"), nullptr); 206 ASSERT_EQ(SrcMgr::ContentCache::getInvalidBOM("\xFF\xFF\xFF"), nullptr); 207 ASSERT_EQ(SrcMgr::ContentCache::getInvalidBOM("#include <iostream>"), 208 nullptr); 209 210 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM( 211 "\xFE\xFF#include <iostream>")), 212 "UTF-16 (BE)"); 213 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM( 214 "\xFF\xFE#include <iostream>")), 215 "UTF-16 (LE)"); 216 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM( 217 "\x2B\x2F\x76#include <iostream>")), 218 "UTF-7"); 219 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM( 220 "\xF7\x64\x4C#include <iostream>")), 221 "UTF-1"); 222 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM( 223 "\xDD\x73\x66\x73#include <iostream>")), 224 "UTF-EBCDIC"); 225 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM( 226 "\x0E\xFE\xFF#include <iostream>")), 227 "SCSU"); 228 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM( 229 "\xFB\xEE\x28#include <iostream>")), 230 "BOCU-1"); 231 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM( 232 "\x84\x31\x95\x33#include <iostream>")), 233 "GB-18030"); 234 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM( 235 llvm::StringLiteral::withInnerNUL( 236 "\x00\x00\xFE\xFF#include <iostream>"))), 237 "UTF-32 (BE)"); 238 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM( 239 llvm::StringLiteral::withInnerNUL( 240 "\xFF\xFE\x00\x00#include <iostream>"))), 241 "UTF-32 (LE)"); 242 } 243 244 #if defined(LLVM_ON_UNIX) 245 246 TEST_F(SourceManagerTest, getMacroArgExpandedLocation) { 247 const char *header = 248 "#define FM(x,y) x\n"; 249 250 const char *main = 251 "#include \"/test-header.h\"\n" 252 "#define VAL 0\n" 253 "FM(VAL,0)\n" 254 "FM(0,VAL)\n" 255 "FM(FM(0,VAL),0)\n" 256 "#define CONCAT(X, Y) X##Y\n" 257 "CONCAT(1,1)\n"; 258 259 std::unique_ptr<llvm::MemoryBuffer> HeaderBuf = 260 llvm::MemoryBuffer::getMemBuffer(header); 261 std::unique_ptr<llvm::MemoryBuffer> MainBuf = 262 llvm::MemoryBuffer::getMemBuffer(main); 263 FileID mainFileID = SourceMgr.createFileID(std::move(MainBuf)); 264 SourceMgr.setMainFileID(mainFileID); 265 266 const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h", 267 HeaderBuf->getBufferSize(), 0); 268 SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf)); 269 270 TrivialModuleLoader ModLoader; 271 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr, 272 Diags, LangOpts, &*Target); 273 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts, 274 SourceMgr, HeaderInfo, ModLoader, 275 /*IILookup =*/nullptr, 276 /*OwnsHeaderSearch =*/false); 277 PP.Initialize(*Target); 278 PP.EnterMainSourceFile(); 279 280 std::vector<Token> toks; 281 while (1) { 282 Token tok; 283 PP.Lex(tok); 284 if (tok.is(tok::eof)) 285 break; 286 toks.push_back(tok); 287 } 288 289 // Make sure we got the tokens that we expected. 290 ASSERT_EQ(4U, toks.size()); 291 ASSERT_EQ(tok::numeric_constant, toks[0].getKind()); 292 ASSERT_EQ(tok::numeric_constant, toks[1].getKind()); 293 ASSERT_EQ(tok::numeric_constant, toks[2].getKind()); 294 ASSERT_EQ(tok::numeric_constant, toks[3].getKind()); 295 296 SourceLocation defLoc = SourceMgr.translateLineCol(mainFileID, 2, 13); 297 SourceLocation loc1 = SourceMgr.translateLineCol(mainFileID, 3, 8); 298 SourceLocation loc2 = SourceMgr.translateLineCol(mainFileID, 4, 4); 299 SourceLocation loc3 = SourceMgr.translateLineCol(mainFileID, 5, 7); 300 SourceLocation defLoc2 = SourceMgr.translateLineCol(mainFileID, 6, 22); 301 defLoc = SourceMgr.getMacroArgExpandedLocation(defLoc); 302 loc1 = SourceMgr.getMacroArgExpandedLocation(loc1); 303 loc2 = SourceMgr.getMacroArgExpandedLocation(loc2); 304 loc3 = SourceMgr.getMacroArgExpandedLocation(loc3); 305 defLoc2 = SourceMgr.getMacroArgExpandedLocation(defLoc2); 306 307 EXPECT_TRUE(defLoc.isFileID()); 308 EXPECT_TRUE(loc1.isFileID()); 309 EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc2)); 310 EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc3)); 311 EXPECT_EQ(loc2, toks[1].getLocation()); 312 EXPECT_EQ(loc3, toks[2].getLocation()); 313 EXPECT_TRUE(defLoc2.isFileID()); 314 } 315 316 namespace { 317 318 struct MacroAction { 319 enum Kind { kExpansion, kDefinition, kUnDefinition}; 320 321 SourceLocation Loc; 322 std::string Name; 323 unsigned MAKind : 3; 324 325 MacroAction(SourceLocation Loc, StringRef Name, unsigned K) 326 : Loc(Loc), Name(Name), MAKind(K) { } 327 328 bool isExpansion() const { return MAKind == kExpansion; } 329 bool isDefinition() const { return MAKind & kDefinition; } 330 bool isUnDefinition() const { return MAKind & kUnDefinition; } 331 }; 332 333 class MacroTracker : public PPCallbacks { 334 std::vector<MacroAction> &Macros; 335 336 public: 337 explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) { } 338 339 void MacroDefined(const Token &MacroNameTok, 340 const MacroDirective *MD) override { 341 Macros.push_back(MacroAction(MD->getLocation(), 342 MacroNameTok.getIdentifierInfo()->getName(), 343 MacroAction::kDefinition)); 344 } 345 void MacroUndefined(const Token &MacroNameTok, 346 const MacroDefinition &MD, 347 const MacroDirective *UD) override { 348 Macros.push_back( 349 MacroAction(UD ? UD->getLocation() : SourceLocation(), 350 MacroNameTok.getIdentifierInfo()->getName(), 351 UD ? MacroAction::kDefinition | MacroAction::kUnDefinition 352 : MacroAction::kUnDefinition)); 353 } 354 void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, 355 SourceRange Range, const MacroArgs *Args) override { 356 Macros.push_back(MacroAction(MacroNameTok.getLocation(), 357 MacroNameTok.getIdentifierInfo()->getName(), 358 MacroAction::kExpansion)); 359 } 360 }; 361 362 } 363 364 TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) { 365 const char *header = 366 "#define MACRO_IN_INCLUDE 0\n" 367 "#define MACRO_DEFINED\n" 368 "#undef MACRO_DEFINED\n" 369 "#undef MACRO_UNDEFINED\n"; 370 371 const char *main = 372 "#define M(x) x\n" 373 "#define INC \"/test-header.h\"\n" 374 "#include M(INC)\n" 375 "#define INC2 </test-header.h>\n" 376 "#include M(INC2)\n"; 377 378 std::unique_ptr<llvm::MemoryBuffer> HeaderBuf = 379 llvm::MemoryBuffer::getMemBuffer(header); 380 std::unique_ptr<llvm::MemoryBuffer> MainBuf = 381 llvm::MemoryBuffer::getMemBuffer(main); 382 SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(MainBuf))); 383 384 const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h", 385 HeaderBuf->getBufferSize(), 0); 386 SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf)); 387 388 TrivialModuleLoader ModLoader; 389 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr, 390 Diags, LangOpts, &*Target); 391 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts, 392 SourceMgr, HeaderInfo, ModLoader, 393 /*IILookup =*/nullptr, 394 /*OwnsHeaderSearch =*/false); 395 PP.Initialize(*Target); 396 397 std::vector<MacroAction> Macros; 398 PP.addPPCallbacks(std::make_unique<MacroTracker>(Macros)); 399 400 PP.EnterMainSourceFile(); 401 402 std::vector<Token> toks; 403 while (1) { 404 Token tok; 405 PP.Lex(tok); 406 if (tok.is(tok::eof)) 407 break; 408 toks.push_back(tok); 409 } 410 411 // Make sure we got the tokens that we expected. 412 ASSERT_EQ(0U, toks.size()); 413 414 ASSERT_EQ(15U, Macros.size()); 415 // #define M(x) x 416 ASSERT_TRUE(Macros[0].isDefinition()); 417 ASSERT_EQ("M", Macros[0].Name); 418 // #define INC "/test-header.h" 419 ASSERT_TRUE(Macros[1].isDefinition()); 420 ASSERT_EQ("INC", Macros[1].Name); 421 // M expansion in #include M(INC) 422 ASSERT_FALSE(Macros[2].isDefinition()); 423 ASSERT_EQ("M", Macros[2].Name); 424 // INC expansion in #include M(INC) 425 ASSERT_TRUE(Macros[3].isExpansion()); 426 ASSERT_EQ("INC", Macros[3].Name); 427 // #define MACRO_IN_INCLUDE 0 428 ASSERT_TRUE(Macros[4].isDefinition()); 429 ASSERT_EQ("MACRO_IN_INCLUDE", Macros[4].Name); 430 // #define MACRO_DEFINED 431 ASSERT_TRUE(Macros[5].isDefinition()); 432 ASSERT_FALSE(Macros[5].isUnDefinition()); 433 ASSERT_EQ("MACRO_DEFINED", Macros[5].Name); 434 // #undef MACRO_DEFINED 435 ASSERT_TRUE(Macros[6].isDefinition()); 436 ASSERT_TRUE(Macros[6].isUnDefinition()); 437 ASSERT_EQ("MACRO_DEFINED", Macros[6].Name); 438 // #undef MACRO_UNDEFINED 439 ASSERT_FALSE(Macros[7].isDefinition()); 440 ASSERT_TRUE(Macros[7].isUnDefinition()); 441 ASSERT_EQ("MACRO_UNDEFINED", Macros[7].Name); 442 // #define INC2 </test-header.h> 443 ASSERT_TRUE(Macros[8].isDefinition()); 444 ASSERT_EQ("INC2", Macros[8].Name); 445 // M expansion in #include M(INC2) 446 ASSERT_FALSE(Macros[9].isDefinition()); 447 ASSERT_EQ("M", Macros[9].Name); 448 // INC2 expansion in #include M(INC2) 449 ASSERT_TRUE(Macros[10].isExpansion()); 450 ASSERT_EQ("INC2", Macros[10].Name); 451 // #define MACRO_IN_INCLUDE 0 452 ASSERT_TRUE(Macros[11].isDefinition()); 453 ASSERT_EQ("MACRO_IN_INCLUDE", Macros[11].Name); 454 455 // The INC expansion in #include M(INC) comes before the first 456 // MACRO_IN_INCLUDE definition of the included file. 457 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[3].Loc, Macros[4].Loc)); 458 459 // The INC2 expansion in #include M(INC2) comes before the second 460 // MACRO_IN_INCLUDE definition of the included file. 461 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[10].Loc, Macros[11].Loc)); 462 } 463 464 #endif 465 466 } // anonymous namespace 467