1 //===- unittests/Basic/SourceManagerTest.cpp ------ SourceManager tests ---===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "clang/Basic/SourceManager.h" 11 #include "clang/Basic/Diagnostic.h" 12 #include "clang/Basic/DiagnosticOptions.h" 13 #include "clang/Basic/FileManager.h" 14 #include "clang/Basic/LangOptions.h" 15 #include "clang/Basic/MemoryBufferCache.h" 16 #include "clang/Basic/TargetInfo.h" 17 #include "clang/Basic/TargetOptions.h" 18 #include "clang/Lex/HeaderSearch.h" 19 #include "clang/Lex/HeaderSearchOptions.h" 20 #include "clang/Lex/ModuleLoader.h" 21 #include "clang/Lex/Preprocessor.h" 22 #include "clang/Lex/PreprocessorOptions.h" 23 #include "llvm/ADT/SmallString.h" 24 #include "llvm/Config/llvm-config.h" 25 #include "gtest/gtest.h" 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 class VoidModuleLoader : public ModuleLoader { 55 ModuleLoadResult loadModule(SourceLocation ImportLoc, 56 ModuleIdPath Path, 57 Module::NameVisibilityKind Visibility, 58 bool IsInclusionDirective) override { 59 return ModuleLoadResult(); 60 } 61 62 void makeModuleVisible(Module *Mod, 63 Module::NameVisibilityKind Visibility, 64 SourceLocation ImportLoc) override { } 65 66 GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override 67 { return nullptr; } 68 bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override 69 { return 0; } 70 }; 71 72 TEST_F(SourceManagerTest, isBeforeInTranslationUnit) { 73 const char *source = 74 "#define M(x) [x]\n" 75 "M(foo)"; 76 std::unique_ptr<llvm::MemoryBuffer> Buf = 77 llvm::MemoryBuffer::getMemBuffer(source); 78 FileID mainFileID = SourceMgr.createFileID(std::move(Buf)); 79 SourceMgr.setMainFileID(mainFileID); 80 81 VoidModuleLoader ModLoader; 82 MemoryBufferCache PCMCache; 83 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr, 84 Diags, LangOpts, &*Target); 85 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts, 86 SourceMgr, PCMCache, HeaderInfo, ModLoader, 87 /*IILookup =*/nullptr, 88 /*OwnsHeaderSearch =*/false); 89 PP.Initialize(*Target); 90 PP.EnterMainSourceFile(); 91 92 std::vector<Token> toks; 93 while (1) { 94 Token tok; 95 PP.Lex(tok); 96 if (tok.is(tok::eof)) 97 break; 98 toks.push_back(tok); 99 } 100 101 // Make sure we got the tokens that we expected. 102 ASSERT_EQ(3U, toks.size()); 103 ASSERT_EQ(tok::l_square, toks[0].getKind()); 104 ASSERT_EQ(tok::identifier, toks[1].getKind()); 105 ASSERT_EQ(tok::r_square, toks[2].getKind()); 106 107 SourceLocation lsqrLoc = toks[0].getLocation(); 108 SourceLocation idLoc = toks[1].getLocation(); 109 SourceLocation rsqrLoc = toks[2].getLocation(); 110 111 SourceLocation macroExpStartLoc = SourceMgr.translateLineCol(mainFileID, 2, 1); 112 SourceLocation macroExpEndLoc = SourceMgr.translateLineCol(mainFileID, 2, 6); 113 ASSERT_TRUE(macroExpStartLoc.isFileID()); 114 ASSERT_TRUE(macroExpEndLoc.isFileID()); 115 116 SmallString<32> str; 117 ASSERT_EQ("M", PP.getSpelling(macroExpStartLoc, str)); 118 ASSERT_EQ(")", PP.getSpelling(macroExpEndLoc, str)); 119 120 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(lsqrLoc, idLoc)); 121 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, rsqrLoc)); 122 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(macroExpStartLoc, idLoc)); 123 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, macroExpEndLoc)); 124 } 125 126 TEST_F(SourceManagerTest, getColumnNumber) { 127 const char *Source = 128 "int x;\n" 129 "int y;"; 130 131 std::unique_ptr<llvm::MemoryBuffer> Buf = 132 llvm::MemoryBuffer::getMemBuffer(Source); 133 FileID MainFileID = SourceMgr.createFileID(std::move(Buf)); 134 SourceMgr.setMainFileID(MainFileID); 135 136 bool Invalid; 137 138 Invalid = false; 139 EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 0, &Invalid)); 140 EXPECT_TRUE(!Invalid); 141 142 Invalid = false; 143 EXPECT_EQ(5U, SourceMgr.getColumnNumber(MainFileID, 4, &Invalid)); 144 EXPECT_TRUE(!Invalid); 145 146 Invalid = false; 147 EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 7, &Invalid)); 148 EXPECT_TRUE(!Invalid); 149 150 Invalid = false; 151 EXPECT_EQ(5U, SourceMgr.getColumnNumber(MainFileID, 11, &Invalid)); 152 EXPECT_TRUE(!Invalid); 153 154 Invalid = false; 155 EXPECT_EQ(7U, SourceMgr.getColumnNumber(MainFileID, strlen(Source), 156 &Invalid)); 157 EXPECT_TRUE(!Invalid); 158 159 Invalid = false; 160 SourceMgr.getColumnNumber(MainFileID, strlen(Source)+1, &Invalid); 161 EXPECT_TRUE(Invalid); 162 163 // Test invalid files 164 Invalid = false; 165 SourceMgr.getColumnNumber(FileID(), 0, &Invalid); 166 EXPECT_TRUE(Invalid); 167 168 Invalid = false; 169 SourceMgr.getColumnNumber(FileID(), 1, &Invalid); 170 EXPECT_TRUE(Invalid); 171 172 // Test with no invalid flag. 173 EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 0, nullptr)); 174 } 175 176 #if defined(LLVM_ON_UNIX) 177 178 TEST_F(SourceManagerTest, getMacroArgExpandedLocation) { 179 const char *header = 180 "#define FM(x,y) x\n"; 181 182 const char *main = 183 "#include \"/test-header.h\"\n" 184 "#define VAL 0\n" 185 "FM(VAL,0)\n" 186 "FM(0,VAL)\n" 187 "FM(FM(0,VAL),0)\n" 188 "#define CONCAT(X, Y) X##Y\n" 189 "CONCAT(1,1)\n"; 190 191 std::unique_ptr<llvm::MemoryBuffer> HeaderBuf = 192 llvm::MemoryBuffer::getMemBuffer(header); 193 std::unique_ptr<llvm::MemoryBuffer> MainBuf = 194 llvm::MemoryBuffer::getMemBuffer(main); 195 FileID mainFileID = SourceMgr.createFileID(std::move(MainBuf)); 196 SourceMgr.setMainFileID(mainFileID); 197 198 const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h", 199 HeaderBuf->getBufferSize(), 0); 200 SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf)); 201 202 VoidModuleLoader ModLoader; 203 MemoryBufferCache PCMCache; 204 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr, 205 Diags, LangOpts, &*Target); 206 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts, 207 SourceMgr, PCMCache, HeaderInfo, ModLoader, 208 /*IILookup =*/nullptr, 209 /*OwnsHeaderSearch =*/false); 210 PP.Initialize(*Target); 211 PP.EnterMainSourceFile(); 212 213 std::vector<Token> toks; 214 while (1) { 215 Token tok; 216 PP.Lex(tok); 217 if (tok.is(tok::eof)) 218 break; 219 toks.push_back(tok); 220 } 221 222 // Make sure we got the tokens that we expected. 223 ASSERT_EQ(4U, toks.size()); 224 ASSERT_EQ(tok::numeric_constant, toks[0].getKind()); 225 ASSERT_EQ(tok::numeric_constant, toks[1].getKind()); 226 ASSERT_EQ(tok::numeric_constant, toks[2].getKind()); 227 ASSERT_EQ(tok::numeric_constant, toks[3].getKind()); 228 229 SourceLocation defLoc = SourceMgr.translateLineCol(mainFileID, 2, 13); 230 SourceLocation loc1 = SourceMgr.translateLineCol(mainFileID, 3, 8); 231 SourceLocation loc2 = SourceMgr.translateLineCol(mainFileID, 4, 4); 232 SourceLocation loc3 = SourceMgr.translateLineCol(mainFileID, 5, 7); 233 SourceLocation defLoc2 = SourceMgr.translateLineCol(mainFileID, 6, 22); 234 defLoc = SourceMgr.getMacroArgExpandedLocation(defLoc); 235 loc1 = SourceMgr.getMacroArgExpandedLocation(loc1); 236 loc2 = SourceMgr.getMacroArgExpandedLocation(loc2); 237 loc3 = SourceMgr.getMacroArgExpandedLocation(loc3); 238 defLoc2 = SourceMgr.getMacroArgExpandedLocation(defLoc2); 239 240 EXPECT_TRUE(defLoc.isFileID()); 241 EXPECT_TRUE(loc1.isFileID()); 242 EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc2)); 243 EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc3)); 244 EXPECT_EQ(loc2, toks[1].getLocation()); 245 EXPECT_EQ(loc3, toks[2].getLocation()); 246 EXPECT_TRUE(defLoc2.isFileID()); 247 } 248 249 namespace { 250 251 struct MacroAction { 252 enum Kind { kExpansion, kDefinition, kUnDefinition}; 253 254 SourceLocation Loc; 255 std::string Name; 256 unsigned MAKind : 3; 257 258 MacroAction(SourceLocation Loc, StringRef Name, unsigned K) 259 : Loc(Loc), Name(Name), MAKind(K) { } 260 261 bool isExpansion() const { return MAKind == kExpansion; } 262 bool isDefinition() const { return MAKind & kDefinition; } 263 bool isUnDefinition() const { return MAKind & kUnDefinition; } 264 }; 265 266 class MacroTracker : public PPCallbacks { 267 std::vector<MacroAction> &Macros; 268 269 public: 270 explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) { } 271 272 void MacroDefined(const Token &MacroNameTok, 273 const MacroDirective *MD) override { 274 Macros.push_back(MacroAction(MD->getLocation(), 275 MacroNameTok.getIdentifierInfo()->getName(), 276 MacroAction::kDefinition)); 277 } 278 void MacroUndefined(const Token &MacroNameTok, 279 const MacroDefinition &MD, 280 const MacroDirective *UD) override { 281 Macros.push_back( 282 MacroAction(UD ? UD->getLocation() : SourceLocation(), 283 MacroNameTok.getIdentifierInfo()->getName(), 284 UD ? MacroAction::kDefinition | MacroAction::kUnDefinition 285 : MacroAction::kUnDefinition)); 286 } 287 void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, 288 SourceRange Range, const MacroArgs *Args) override { 289 Macros.push_back(MacroAction(MacroNameTok.getLocation(), 290 MacroNameTok.getIdentifierInfo()->getName(), 291 MacroAction::kExpansion)); 292 } 293 }; 294 295 } 296 297 TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) { 298 const char *header = 299 "#define MACRO_IN_INCLUDE 0\n" 300 "#define MACRO_DEFINED\n" 301 "#undef MACRO_DEFINED\n" 302 "#undef MACRO_UNDEFINED\n"; 303 304 const char *main = 305 "#define M(x) x\n" 306 "#define INC \"/test-header.h\"\n" 307 "#include M(INC)\n" 308 "#define INC2 </test-header.h>\n" 309 "#include M(INC2)\n"; 310 311 std::unique_ptr<llvm::MemoryBuffer> HeaderBuf = 312 llvm::MemoryBuffer::getMemBuffer(header); 313 std::unique_ptr<llvm::MemoryBuffer> MainBuf = 314 llvm::MemoryBuffer::getMemBuffer(main); 315 SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(MainBuf))); 316 317 const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h", 318 HeaderBuf->getBufferSize(), 0); 319 SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf)); 320 321 VoidModuleLoader ModLoader; 322 MemoryBufferCache PCMCache; 323 HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr, 324 Diags, LangOpts, &*Target); 325 Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts, 326 SourceMgr, PCMCache, HeaderInfo, ModLoader, 327 /*IILookup =*/nullptr, 328 /*OwnsHeaderSearch =*/false); 329 PP.Initialize(*Target); 330 331 std::vector<MacroAction> Macros; 332 PP.addPPCallbacks(llvm::make_unique<MacroTracker>(Macros)); 333 334 PP.EnterMainSourceFile(); 335 336 std::vector<Token> toks; 337 while (1) { 338 Token tok; 339 PP.Lex(tok); 340 if (tok.is(tok::eof)) 341 break; 342 toks.push_back(tok); 343 } 344 345 // Make sure we got the tokens that we expected. 346 ASSERT_EQ(0U, toks.size()); 347 348 ASSERT_EQ(15U, Macros.size()); 349 // #define M(x) x 350 ASSERT_TRUE(Macros[0].isDefinition()); 351 ASSERT_EQ("M", Macros[0].Name); 352 // #define INC "/test-header.h" 353 ASSERT_TRUE(Macros[1].isDefinition()); 354 ASSERT_EQ("INC", Macros[1].Name); 355 // M expansion in #include M(INC) 356 ASSERT_FALSE(Macros[2].isDefinition()); 357 ASSERT_EQ("M", Macros[2].Name); 358 // INC expansion in #include M(INC) 359 ASSERT_TRUE(Macros[3].isExpansion()); 360 ASSERT_EQ("INC", Macros[3].Name); 361 // #define MACRO_IN_INCLUDE 0 362 ASSERT_TRUE(Macros[4].isDefinition()); 363 ASSERT_EQ("MACRO_IN_INCLUDE", Macros[4].Name); 364 // #define MACRO_DEFINED 365 ASSERT_TRUE(Macros[5].isDefinition()); 366 ASSERT_FALSE(Macros[5].isUnDefinition()); 367 ASSERT_EQ("MACRO_DEFINED", Macros[5].Name); 368 // #undef MACRO_DEFINED 369 ASSERT_TRUE(Macros[6].isDefinition()); 370 ASSERT_TRUE(Macros[6].isUnDefinition()); 371 ASSERT_EQ("MACRO_DEFINED", Macros[6].Name); 372 // #undef MACRO_UNDEFINED 373 ASSERT_FALSE(Macros[7].isDefinition()); 374 ASSERT_TRUE(Macros[7].isUnDefinition()); 375 ASSERT_EQ("MACRO_UNDEFINED", Macros[7].Name); 376 // #define INC2 </test-header.h> 377 ASSERT_TRUE(Macros[8].isDefinition()); 378 ASSERT_EQ("INC2", Macros[8].Name); 379 // M expansion in #include M(INC2) 380 ASSERT_FALSE(Macros[9].isDefinition()); 381 ASSERT_EQ("M", Macros[9].Name); 382 // INC2 expansion in #include M(INC2) 383 ASSERT_TRUE(Macros[10].isExpansion()); 384 ASSERT_EQ("INC2", Macros[10].Name); 385 // #define MACRO_IN_INCLUDE 0 386 ASSERT_TRUE(Macros[11].isDefinition()); 387 ASSERT_EQ("MACRO_IN_INCLUDE", Macros[11].Name); 388 389 // The INC expansion in #include M(INC) comes before the first 390 // MACRO_IN_INCLUDE definition of the included file. 391 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[3].Loc, Macros[4].Loc)); 392 393 // The INC2 expansion in #include M(INC2) comes before the second 394 // MACRO_IN_INCLUDE definition of the included file. 395 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[10].Loc, Macros[11].Loc)); 396 } 397 398 #endif 399 400 } // anonymous namespace 401