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 #if defined(LLVM_ON_UNIX) 204 205 TEST_F(SourceManagerTest, getMacroArgExpandedLocation) { 206 const char *header = 207 "#define FM(x,y) x\n"; 208 209 const char *main = 210 "#include \"/test-header.h\"\n" 211 "#define VAL 0\n" 212 "FM(VAL,0)\n" 213 "FM(0,VAL)\n" 214 "FM(FM(0,VAL),0)\n" 215 "#define CONCAT(X, Y) X##Y\n" 216 "CONCAT(1,1)\n"; 217 218 std::unique_ptr<llvm::MemoryBuffer> HeaderBuf = 219 llvm::MemoryBuffer::getMemBuffer(header); 220 std::unique_ptr<llvm::MemoryBuffer> MainBuf = 221 llvm::MemoryBuffer::getMemBuffer(main); 222 FileID mainFileID = SourceMgr.createFileID(std::move(MainBuf)); 223 SourceMgr.setMainFileID(mainFileID); 224 225 const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h", 226 HeaderBuf->getBufferSize(), 0); 227 SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf)); 228 229 TrivialModuleLoader ModLoader; 230 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr, 231 Diags, LangOpts, &*Target); 232 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts, 233 SourceMgr, HeaderInfo, ModLoader, 234 /*IILookup =*/nullptr, 235 /*OwnsHeaderSearch =*/false); 236 PP.Initialize(*Target); 237 PP.EnterMainSourceFile(); 238 239 std::vector<Token> toks; 240 while (1) { 241 Token tok; 242 PP.Lex(tok); 243 if (tok.is(tok::eof)) 244 break; 245 toks.push_back(tok); 246 } 247 248 // Make sure we got the tokens that we expected. 249 ASSERT_EQ(4U, toks.size()); 250 ASSERT_EQ(tok::numeric_constant, toks[0].getKind()); 251 ASSERT_EQ(tok::numeric_constant, toks[1].getKind()); 252 ASSERT_EQ(tok::numeric_constant, toks[2].getKind()); 253 ASSERT_EQ(tok::numeric_constant, toks[3].getKind()); 254 255 SourceLocation defLoc = SourceMgr.translateLineCol(mainFileID, 2, 13); 256 SourceLocation loc1 = SourceMgr.translateLineCol(mainFileID, 3, 8); 257 SourceLocation loc2 = SourceMgr.translateLineCol(mainFileID, 4, 4); 258 SourceLocation loc3 = SourceMgr.translateLineCol(mainFileID, 5, 7); 259 SourceLocation defLoc2 = SourceMgr.translateLineCol(mainFileID, 6, 22); 260 defLoc = SourceMgr.getMacroArgExpandedLocation(defLoc); 261 loc1 = SourceMgr.getMacroArgExpandedLocation(loc1); 262 loc2 = SourceMgr.getMacroArgExpandedLocation(loc2); 263 loc3 = SourceMgr.getMacroArgExpandedLocation(loc3); 264 defLoc2 = SourceMgr.getMacroArgExpandedLocation(defLoc2); 265 266 EXPECT_TRUE(defLoc.isFileID()); 267 EXPECT_TRUE(loc1.isFileID()); 268 EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc2)); 269 EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc3)); 270 EXPECT_EQ(loc2, toks[1].getLocation()); 271 EXPECT_EQ(loc3, toks[2].getLocation()); 272 EXPECT_TRUE(defLoc2.isFileID()); 273 } 274 275 namespace { 276 277 struct MacroAction { 278 enum Kind { kExpansion, kDefinition, kUnDefinition}; 279 280 SourceLocation Loc; 281 std::string Name; 282 unsigned MAKind : 3; 283 284 MacroAction(SourceLocation Loc, StringRef Name, unsigned K) 285 : Loc(Loc), Name(Name), MAKind(K) { } 286 287 bool isExpansion() const { return MAKind == kExpansion; } 288 bool isDefinition() const { return MAKind & kDefinition; } 289 bool isUnDefinition() const { return MAKind & kUnDefinition; } 290 }; 291 292 class MacroTracker : public PPCallbacks { 293 std::vector<MacroAction> &Macros; 294 295 public: 296 explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) { } 297 298 void MacroDefined(const Token &MacroNameTok, 299 const MacroDirective *MD) override { 300 Macros.push_back(MacroAction(MD->getLocation(), 301 MacroNameTok.getIdentifierInfo()->getName(), 302 MacroAction::kDefinition)); 303 } 304 void MacroUndefined(const Token &MacroNameTok, 305 const MacroDefinition &MD, 306 const MacroDirective *UD) override { 307 Macros.push_back( 308 MacroAction(UD ? UD->getLocation() : SourceLocation(), 309 MacroNameTok.getIdentifierInfo()->getName(), 310 UD ? MacroAction::kDefinition | MacroAction::kUnDefinition 311 : MacroAction::kUnDefinition)); 312 } 313 void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, 314 SourceRange Range, const MacroArgs *Args) override { 315 Macros.push_back(MacroAction(MacroNameTok.getLocation(), 316 MacroNameTok.getIdentifierInfo()->getName(), 317 MacroAction::kExpansion)); 318 } 319 }; 320 321 } 322 323 TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) { 324 const char *header = 325 "#define MACRO_IN_INCLUDE 0\n" 326 "#define MACRO_DEFINED\n" 327 "#undef MACRO_DEFINED\n" 328 "#undef MACRO_UNDEFINED\n"; 329 330 const char *main = 331 "#define M(x) x\n" 332 "#define INC \"/test-header.h\"\n" 333 "#include M(INC)\n" 334 "#define INC2 </test-header.h>\n" 335 "#include M(INC2)\n"; 336 337 std::unique_ptr<llvm::MemoryBuffer> HeaderBuf = 338 llvm::MemoryBuffer::getMemBuffer(header); 339 std::unique_ptr<llvm::MemoryBuffer> MainBuf = 340 llvm::MemoryBuffer::getMemBuffer(main); 341 SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(MainBuf))); 342 343 const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h", 344 HeaderBuf->getBufferSize(), 0); 345 SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf)); 346 347 TrivialModuleLoader ModLoader; 348 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr, 349 Diags, LangOpts, &*Target); 350 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts, 351 SourceMgr, HeaderInfo, ModLoader, 352 /*IILookup =*/nullptr, 353 /*OwnsHeaderSearch =*/false); 354 PP.Initialize(*Target); 355 356 std::vector<MacroAction> Macros; 357 PP.addPPCallbacks(llvm::make_unique<MacroTracker>(Macros)); 358 359 PP.EnterMainSourceFile(); 360 361 std::vector<Token> toks; 362 while (1) { 363 Token tok; 364 PP.Lex(tok); 365 if (tok.is(tok::eof)) 366 break; 367 toks.push_back(tok); 368 } 369 370 // Make sure we got the tokens that we expected. 371 ASSERT_EQ(0U, toks.size()); 372 373 ASSERT_EQ(15U, Macros.size()); 374 // #define M(x) x 375 ASSERT_TRUE(Macros[0].isDefinition()); 376 ASSERT_EQ("M", Macros[0].Name); 377 // #define INC "/test-header.h" 378 ASSERT_TRUE(Macros[1].isDefinition()); 379 ASSERT_EQ("INC", Macros[1].Name); 380 // M expansion in #include M(INC) 381 ASSERT_FALSE(Macros[2].isDefinition()); 382 ASSERT_EQ("M", Macros[2].Name); 383 // INC expansion in #include M(INC) 384 ASSERT_TRUE(Macros[3].isExpansion()); 385 ASSERT_EQ("INC", Macros[3].Name); 386 // #define MACRO_IN_INCLUDE 0 387 ASSERT_TRUE(Macros[4].isDefinition()); 388 ASSERT_EQ("MACRO_IN_INCLUDE", Macros[4].Name); 389 // #define MACRO_DEFINED 390 ASSERT_TRUE(Macros[5].isDefinition()); 391 ASSERT_FALSE(Macros[5].isUnDefinition()); 392 ASSERT_EQ("MACRO_DEFINED", Macros[5].Name); 393 // #undef MACRO_DEFINED 394 ASSERT_TRUE(Macros[6].isDefinition()); 395 ASSERT_TRUE(Macros[6].isUnDefinition()); 396 ASSERT_EQ("MACRO_DEFINED", Macros[6].Name); 397 // #undef MACRO_UNDEFINED 398 ASSERT_FALSE(Macros[7].isDefinition()); 399 ASSERT_TRUE(Macros[7].isUnDefinition()); 400 ASSERT_EQ("MACRO_UNDEFINED", Macros[7].Name); 401 // #define INC2 </test-header.h> 402 ASSERT_TRUE(Macros[8].isDefinition()); 403 ASSERT_EQ("INC2", Macros[8].Name); 404 // M expansion in #include M(INC2) 405 ASSERT_FALSE(Macros[9].isDefinition()); 406 ASSERT_EQ("M", Macros[9].Name); 407 // INC2 expansion in #include M(INC2) 408 ASSERT_TRUE(Macros[10].isExpansion()); 409 ASSERT_EQ("INC2", Macros[10].Name); 410 // #define MACRO_IN_INCLUDE 0 411 ASSERT_TRUE(Macros[11].isDefinition()); 412 ASSERT_EQ("MACRO_IN_INCLUDE", Macros[11].Name); 413 414 // The INC expansion in #include M(INC) comes before the first 415 // MACRO_IN_INCLUDE definition of the included file. 416 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[3].Loc, Macros[4].Loc)); 417 418 // The INC2 expansion in #include M(INC2) comes before the second 419 // MACRO_IN_INCLUDE definition of the included file. 420 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[10].Loc, Macros[11].Loc)); 421 } 422 423 #endif 424 425 } // anonymous namespace 426