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