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/FileManager.h" 12#include "clang/Basic/Diagnostic.h" 13#include "clang/Basic/LangOptions.h" 14#include "clang/Basic/TargetOptions.h" 15#include "clang/Basic/TargetInfo.h" 16#include "clang/Lex/ModuleLoader.h" 17#include "clang/Lex/HeaderSearch.h" 18#include "clang/Lex/Preprocessor.h" 19#include "llvm/ADT/SmallString.h" 20#include "llvm/Config/config.h" 21 22#include "gtest/gtest.h" 23 24using namespace llvm; 25using namespace clang; 26 27namespace { 28 29// The test fixture. 30class SourceManagerTest : public ::testing::Test { 31protected: 32 SourceManagerTest() 33 : FileMgr(FileMgrOpts), 34 DiagID(new DiagnosticIDs()), 35 Diags(DiagID, new IgnoringDiagConsumer()), 36 SourceMgr(Diags, FileMgr) { 37 TargetOpts.Triple = "x86_64-apple-darwin11.1.0"; 38 Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts); 39 } 40 41 FileSystemOptions FileMgrOpts; 42 FileManager FileMgr; 43 IntrusiveRefCntPtr<DiagnosticIDs> DiagID; 44 DiagnosticsEngine Diags; 45 SourceManager SourceMgr; 46 LangOptions LangOpts; 47 TargetOptions TargetOpts; 48 IntrusiveRefCntPtr<TargetInfo> Target; 49}; 50 51class VoidModuleLoader : public ModuleLoader { 52 virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path, 53 Module::NameVisibilityKind Visibility, 54 bool IsInclusionDirective) { 55 return 0; 56 } 57}; 58 59TEST_F(SourceManagerTest, isBeforeInTranslationUnit) { 60 const char *source = 61 "#define M(x) [x]\n" 62 "M(foo)"; 63 MemoryBuffer *buf = MemoryBuffer::getMemBuffer(source); 64 FileID mainFileID = SourceMgr.createMainFileIDForMemBuffer(buf); 65 66 VoidModuleLoader ModLoader; 67 HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, &*Target); 68 Preprocessor PP(Diags, LangOpts, 69 Target.getPtr(), 70 SourceMgr, HeaderInfo, ModLoader, 71 /*IILookup =*/ 0, 72 /*OwnsHeaderSearch =*/false, 73 /*DelayInitialization =*/ false); 74 PP.EnterMainSourceFile(); 75 76 std::vector<Token> toks; 77 while (1) { 78 Token tok; 79 PP.Lex(tok); 80 if (tok.is(tok::eof)) 81 break; 82 toks.push_back(tok); 83 } 84 85 // Make sure we got the tokens that we expected. 86 ASSERT_EQ(3U, toks.size()); 87 ASSERT_EQ(tok::l_square, toks[0].getKind()); 88 ASSERT_EQ(tok::identifier, toks[1].getKind()); 89 ASSERT_EQ(tok::r_square, toks[2].getKind()); 90 91 SourceLocation lsqrLoc = toks[0].getLocation(); 92 SourceLocation idLoc = toks[1].getLocation(); 93 SourceLocation rsqrLoc = toks[2].getLocation(); 94 95 SourceLocation macroExpStartLoc = SourceMgr.translateLineCol(mainFileID, 2, 1); 96 SourceLocation macroExpEndLoc = SourceMgr.translateLineCol(mainFileID, 2, 6); 97 ASSERT_TRUE(macroExpStartLoc.isFileID()); 98 ASSERT_TRUE(macroExpEndLoc.isFileID()); 99 100 SmallString<32> str; 101 ASSERT_EQ("M", PP.getSpelling(macroExpStartLoc, str)); 102 ASSERT_EQ(")", PP.getSpelling(macroExpEndLoc, str)); 103 104 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(lsqrLoc, idLoc)); 105 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, rsqrLoc)); 106 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(macroExpStartLoc, idLoc)); 107 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, macroExpEndLoc)); 108} 109 110TEST_F(SourceManagerTest, getColumnNumber) { 111 const char *Source = 112 "int x;\n" 113 "int y;"; 114 115 MemoryBuffer *Buf = MemoryBuffer::getMemBuffer(Source); 116 FileID MainFileID = SourceMgr.createMainFileIDForMemBuffer(Buf); 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, NULL)); 156} 157 158#if defined(LLVM_ON_UNIX) 159 160TEST_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 MemoryBuffer *headerBuf = MemoryBuffer::getMemBuffer(header); 174 MemoryBuffer *mainBuf = MemoryBuffer::getMemBuffer(main); 175 FileID mainFileID = SourceMgr.createMainFileIDForMemBuffer(mainBuf); 176 177 const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h", 178 headerBuf->getBufferSize(), 0); 179 SourceMgr.overrideFileContents(headerFile, headerBuf); 180 181 VoidModuleLoader ModLoader; 182 HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, &*Target); 183 Preprocessor PP(Diags, LangOpts, 184 Target.getPtr(), 185 SourceMgr, HeaderInfo, ModLoader, 186 /*IILookup =*/ 0, 187 /*OwnsHeaderSearch =*/false, 188 /*DelayInitialization =*/ false); 189 PP.EnterMainSourceFile(); 190 191 std::vector<Token> toks; 192 while (1) { 193 Token tok; 194 PP.Lex(tok); 195 if (tok.is(tok::eof)) 196 break; 197 toks.push_back(tok); 198 } 199 200 // Make sure we got the tokens that we expected. 201 ASSERT_EQ(4U, toks.size()); 202 ASSERT_EQ(tok::numeric_constant, toks[0].getKind()); 203 ASSERT_EQ(tok::numeric_constant, toks[1].getKind()); 204 ASSERT_EQ(tok::numeric_constant, toks[2].getKind()); 205 ASSERT_EQ(tok::numeric_constant, toks[3].getKind()); 206 207 SourceLocation defLoc = SourceMgr.translateLineCol(mainFileID, 2, 13); 208 SourceLocation loc1 = SourceMgr.translateLineCol(mainFileID, 3, 8); 209 SourceLocation loc2 = SourceMgr.translateLineCol(mainFileID, 4, 4); 210 SourceLocation loc3 = SourceMgr.translateLineCol(mainFileID, 5, 7); 211 SourceLocation defLoc2 = SourceMgr.translateLineCol(mainFileID, 6, 22); 212 defLoc = SourceMgr.getMacroArgExpandedLocation(defLoc); 213 loc1 = SourceMgr.getMacroArgExpandedLocation(loc1); 214 loc2 = SourceMgr.getMacroArgExpandedLocation(loc2); 215 loc3 = SourceMgr.getMacroArgExpandedLocation(loc3); 216 defLoc2 = SourceMgr.getMacroArgExpandedLocation(defLoc2); 217 218 EXPECT_TRUE(defLoc.isFileID()); 219 EXPECT_TRUE(loc1.isFileID()); 220 EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc2)); 221 EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc3)); 222 EXPECT_EQ(loc2, toks[1].getLocation()); 223 EXPECT_EQ(loc3, toks[2].getLocation()); 224 EXPECT_TRUE(defLoc2.isFileID()); 225} 226 227namespace { 228 229struct MacroAction { 230 SourceLocation Loc; 231 std::string Name; 232 bool isDefinition; // if false, it is expansion. 233 234 MacroAction(SourceLocation Loc, StringRef Name, bool isDefinition) 235 : Loc(Loc), Name(Name), isDefinition(isDefinition) { } 236}; 237 238class MacroTracker : public PPCallbacks { 239 std::vector<MacroAction> &Macros; 240 241public: 242 explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) { } 243 244 virtual void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) { 245 Macros.push_back(MacroAction(MI->getDefinitionLoc(), 246 MacroNameTok.getIdentifierInfo()->getName(), 247 true)); 248 } 249 virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo* MI, 250 SourceRange Range) { 251 Macros.push_back(MacroAction(MacroNameTok.getLocation(), 252 MacroNameTok.getIdentifierInfo()->getName(), 253 false)); 254 } 255}; 256 257} 258 259TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) { 260 const char *header = 261 "#define MACRO_IN_INCLUDE 0\n"; 262 263 const char *main = 264 "#define M(x) x\n" 265 "#define INC \"/test-header.h\"\n" 266 "#include M(INC)\n" 267 "#define INC2 </test-header.h>\n" 268 "#include M(INC2)\n"; 269 270 MemoryBuffer *headerBuf = MemoryBuffer::getMemBuffer(header); 271 MemoryBuffer *mainBuf = MemoryBuffer::getMemBuffer(main); 272 SourceMgr.createMainFileIDForMemBuffer(mainBuf); 273 274 const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h", 275 headerBuf->getBufferSize(), 0); 276 SourceMgr.overrideFileContents(headerFile, headerBuf); 277 278 VoidModuleLoader ModLoader; 279 HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, &*Target); 280 Preprocessor PP(Diags, LangOpts, 281 Target.getPtr(), 282 SourceMgr, HeaderInfo, ModLoader, 283 /*IILookup =*/ 0, 284 /*OwnsHeaderSearch =*/false, 285 /*DelayInitialization =*/ false); 286 287 std::vector<MacroAction> Macros; 288 PP.addPPCallbacks(new MacroTracker(Macros)); 289 290 PP.EnterMainSourceFile(); 291 292 std::vector<Token> toks; 293 while (1) { 294 Token tok; 295 PP.Lex(tok); 296 if (tok.is(tok::eof)) 297 break; 298 toks.push_back(tok); 299 } 300 301 // Make sure we got the tokens that we expected. 302 ASSERT_EQ(0U, toks.size()); 303 304 ASSERT_EQ(9U, Macros.size()); 305 // #define M(x) x 306 ASSERT_TRUE(Macros[0].isDefinition); 307 ASSERT_EQ("M", Macros[0].Name); 308 // #define INC "/test-header.h" 309 ASSERT_TRUE(Macros[1].isDefinition); 310 ASSERT_EQ("INC", Macros[1].Name); 311 // M expansion in #include M(INC) 312 ASSERT_FALSE(Macros[2].isDefinition); 313 ASSERT_EQ("M", Macros[2].Name); 314 // INC expansion in #include M(INC) 315 ASSERT_FALSE(Macros[3].isDefinition); 316 ASSERT_EQ("INC", Macros[3].Name); 317 // #define MACRO_IN_INCLUDE 0 318 ASSERT_TRUE(Macros[4].isDefinition); 319 ASSERT_EQ("MACRO_IN_INCLUDE", Macros[4].Name); 320 // #define INC2 </test-header.h> 321 ASSERT_TRUE(Macros[5].isDefinition); 322 ASSERT_EQ("INC2", Macros[5].Name); 323 // M expansion in #include M(INC2) 324 ASSERT_FALSE(Macros[6].isDefinition); 325 ASSERT_EQ("M", Macros[6].Name); 326 // INC2 expansion in #include M(INC2) 327 ASSERT_FALSE(Macros[7].isDefinition); 328 ASSERT_EQ("INC2", Macros[7].Name); 329 // #define MACRO_IN_INCLUDE 0 330 ASSERT_TRUE(Macros[8].isDefinition); 331 ASSERT_EQ("MACRO_IN_INCLUDE", Macros[8].Name); 332 333 // The INC expansion in #include M(INC) comes before the first 334 // MACRO_IN_INCLUDE definition of the included file. 335 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[3].Loc, Macros[4].Loc)); 336 337 // The INC2 expansion in #include M(INC2) comes before the second 338 // MACRO_IN_INCLUDE definition of the included file. 339 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[7].Loc, Macros[8].Loc)); 340} 341 342#endif 343 344} // anonymous namespace 345