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 SourceLocation Loc; 253 std::string Name; 254 bool isDefinition; // if false, it is expansion. 255 256 MacroAction(SourceLocation Loc, StringRef Name, bool isDefinition) 257 : Loc(Loc), Name(Name), isDefinition(isDefinition) { } 258 }; 259 260 class MacroTracker : public PPCallbacks { 261 std::vector<MacroAction> &Macros; 262 263 public: 264 explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) { } 265 266 void MacroDefined(const Token &MacroNameTok, 267 const MacroDirective *MD) override { 268 Macros.push_back(MacroAction(MD->getLocation(), 269 MacroNameTok.getIdentifierInfo()->getName(), 270 true)); 271 } 272 void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, 273 SourceRange Range, const MacroArgs *Args) override { 274 Macros.push_back(MacroAction(MacroNameTok.getLocation(), 275 MacroNameTok.getIdentifierInfo()->getName(), 276 false)); 277 } 278 }; 279 280 } 281 282 TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) { 283 const char *header = 284 "#define MACRO_IN_INCLUDE 0\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 VoidModuleLoader 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(9U, 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_FALSE(Macros[3].isDefinition); 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 INC2 </test-header.h> 347 ASSERT_TRUE(Macros[5].isDefinition); 348 ASSERT_EQ("INC2", Macros[5].Name); 349 // M expansion in #include M(INC2) 350 ASSERT_FALSE(Macros[6].isDefinition); 351 ASSERT_EQ("M", Macros[6].Name); 352 // INC2 expansion in #include M(INC2) 353 ASSERT_FALSE(Macros[7].isDefinition); 354 ASSERT_EQ("INC2", Macros[7].Name); 355 // #define MACRO_IN_INCLUDE 0 356 ASSERT_TRUE(Macros[8].isDefinition); 357 ASSERT_EQ("MACRO_IN_INCLUDE", Macros[8].Name); 358 359 // The INC expansion in #include M(INC) comes before the first 360 // MACRO_IN_INCLUDE definition of the included file. 361 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[3].Loc, Macros[4].Loc)); 362 363 // The INC2 expansion in #include M(INC2) comes before the second 364 // MACRO_IN_INCLUDE definition of the included file. 365 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[7].Loc, Macros[8].Loc)); 366 } 367 368 #endif 369 370 } // anonymous namespace 371