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