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/DiagnosticOptions.h" 14 #include "clang/Basic/LangOptions.h" 15 #include "clang/Basic/TargetOptions.h" 16 #include "clang/Basic/TargetInfo.h" 17 #include "clang/Lex/ModuleLoader.h" 18 #include "clang/Lex/HeaderSearch.h" 19 #include "clang/Lex/HeaderSearchOptions.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 25 #include "gtest/gtest.h" 26 27 using namespace llvm; 28 using namespace clang; 29 30 namespace { 31 32 // The test fixture. 33 class SourceManagerTest : public ::testing::Test { 34 protected: 35 SourceManagerTest() 36 : FileMgr(FileMgrOpts), 37 DiagID(new DiagnosticIDs()), 38 Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()), 39 SourceMgr(Diags, FileMgr), 40 TargetOpts(new TargetOptions) { 41 TargetOpts->Triple = "x86_64-apple-darwin11.1.0"; 42 Target = TargetInfo::CreateTargetInfo(Diags, &*TargetOpts); 43 } 44 45 FileSystemOptions FileMgrOpts; 46 FileManager FileMgr; 47 IntrusiveRefCntPtr<DiagnosticIDs> DiagID; 48 DiagnosticsEngine Diags; 49 SourceManager SourceMgr; 50 LangOptions LangOpts; 51 IntrusiveRefCntPtr<TargetOptions> TargetOpts; 52 IntrusiveRefCntPtr<TargetInfo> Target; 53 }; 54 55 class VoidModuleLoader : public ModuleLoader { 56 virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path, 57 Module::NameVisibilityKind Visibility, 58 bool IsInclusionDirective) { 59 return 0; 60 } 61 }; 62 63 TEST_F(SourceManagerTest, isBeforeInTranslationUnit) { 64 const char *source = 65 "#define M(x) [x]\n" 66 "M(foo)"; 67 MemoryBuffer *buf = MemoryBuffer::getMemBuffer(source); 68 FileID mainFileID = SourceMgr.createMainFileIDForMemBuffer(buf); 69 70 VoidModuleLoader ModLoader; 71 HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts, 72 &*Target); 73 Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(), 74 SourceMgr, HeaderInfo, ModLoader, 75 /*IILookup =*/ 0, 76 /*OwnsHeaderSearch =*/false, 77 /*DelayInitialization =*/ false); 78 PP.EnterMainSourceFile(); 79 80 std::vector<Token> toks; 81 while (1) { 82 Token tok; 83 PP.Lex(tok); 84 if (tok.is(tok::eof)) 85 break; 86 toks.push_back(tok); 87 } 88 89 // Make sure we got the tokens that we expected. 90 ASSERT_EQ(3U, toks.size()); 91 ASSERT_EQ(tok::l_square, toks[0].getKind()); 92 ASSERT_EQ(tok::identifier, toks[1].getKind()); 93 ASSERT_EQ(tok::r_square, toks[2].getKind()); 94 95 SourceLocation lsqrLoc = toks[0].getLocation(); 96 SourceLocation idLoc = toks[1].getLocation(); 97 SourceLocation rsqrLoc = toks[2].getLocation(); 98 99 SourceLocation macroExpStartLoc = SourceMgr.translateLineCol(mainFileID, 2, 1); 100 SourceLocation macroExpEndLoc = SourceMgr.translateLineCol(mainFileID, 2, 6); 101 ASSERT_TRUE(macroExpStartLoc.isFileID()); 102 ASSERT_TRUE(macroExpEndLoc.isFileID()); 103 104 SmallString<32> str; 105 ASSERT_EQ("M", PP.getSpelling(macroExpStartLoc, str)); 106 ASSERT_EQ(")", PP.getSpelling(macroExpEndLoc, str)); 107 108 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(lsqrLoc, idLoc)); 109 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, rsqrLoc)); 110 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(macroExpStartLoc, idLoc)); 111 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, macroExpEndLoc)); 112 } 113 114 TEST_F(SourceManagerTest, getColumnNumber) { 115 const char *Source = 116 "int x;\n" 117 "int y;"; 118 119 MemoryBuffer *Buf = MemoryBuffer::getMemBuffer(Source); 120 FileID MainFileID = SourceMgr.createMainFileIDForMemBuffer(Buf); 121 122 bool Invalid; 123 124 Invalid = false; 125 EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 0, &Invalid)); 126 EXPECT_TRUE(!Invalid); 127 128 Invalid = false; 129 EXPECT_EQ(5U, SourceMgr.getColumnNumber(MainFileID, 4, &Invalid)); 130 EXPECT_TRUE(!Invalid); 131 132 Invalid = false; 133 EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 7, &Invalid)); 134 EXPECT_TRUE(!Invalid); 135 136 Invalid = false; 137 EXPECT_EQ(5U, SourceMgr.getColumnNumber(MainFileID, 11, &Invalid)); 138 EXPECT_TRUE(!Invalid); 139 140 Invalid = false; 141 EXPECT_EQ(7U, SourceMgr.getColumnNumber(MainFileID, strlen(Source), 142 &Invalid)); 143 EXPECT_TRUE(!Invalid); 144 145 Invalid = false; 146 SourceMgr.getColumnNumber(MainFileID, strlen(Source)+1, &Invalid); 147 EXPECT_TRUE(Invalid); 148 149 // Test invalid files 150 Invalid = false; 151 SourceMgr.getColumnNumber(FileID(), 0, &Invalid); 152 EXPECT_TRUE(Invalid); 153 154 Invalid = false; 155 SourceMgr.getColumnNumber(FileID(), 1, &Invalid); 156 EXPECT_TRUE(Invalid); 157 158 // Test with no invalid flag. 159 EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 0, NULL)); 160 } 161 162 #if defined(LLVM_ON_UNIX) 163 164 TEST_F(SourceManagerTest, getMacroArgExpandedLocation) { 165 const char *header = 166 "#define FM(x,y) x\n"; 167 168 const char *main = 169 "#include \"/test-header.h\"\n" 170 "#define VAL 0\n" 171 "FM(VAL,0)\n" 172 "FM(0,VAL)\n" 173 "FM(FM(0,VAL),0)\n" 174 "#define CONCAT(X, Y) X##Y\n" 175 "CONCAT(1,1)\n"; 176 177 MemoryBuffer *headerBuf = MemoryBuffer::getMemBuffer(header); 178 MemoryBuffer *mainBuf = MemoryBuffer::getMemBuffer(main); 179 FileID mainFileID = SourceMgr.createMainFileIDForMemBuffer(mainBuf); 180 181 const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h", 182 headerBuf->getBufferSize(), 0); 183 SourceMgr.overrideFileContents(headerFile, headerBuf); 184 185 VoidModuleLoader ModLoader; 186 HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts, 187 &*Target); 188 Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(), 189 SourceMgr, HeaderInfo, ModLoader, 190 /*IILookup =*/ 0, 191 /*OwnsHeaderSearch =*/false, 192 /*DelayInitialization =*/ false); 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 SourceLocation Loc; 235 std::string Name; 236 bool isDefinition; // if false, it is expansion. 237 238 MacroAction(SourceLocation Loc, StringRef Name, bool isDefinition) 239 : Loc(Loc), Name(Name), isDefinition(isDefinition) { } 240 }; 241 242 class MacroTracker : public PPCallbacks { 243 std::vector<MacroAction> &Macros; 244 245 public: 246 explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) { } 247 248 virtual void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) { 249 Macros.push_back(MacroAction(MI->getDefinitionLoc(), 250 MacroNameTok.getIdentifierInfo()->getName(), 251 true)); 252 } 253 virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo* MI, 254 SourceRange Range) { 255 Macros.push_back(MacroAction(MacroNameTok.getLocation(), 256 MacroNameTok.getIdentifierInfo()->getName(), 257 false)); 258 } 259 }; 260 261 } 262 263 TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) { 264 const char *header = 265 "#define MACRO_IN_INCLUDE 0\n"; 266 267 const char *main = 268 "#define M(x) x\n" 269 "#define INC \"/test-header.h\"\n" 270 "#include M(INC)\n" 271 "#define INC2 </test-header.h>\n" 272 "#include M(INC2)\n"; 273 274 MemoryBuffer *headerBuf = MemoryBuffer::getMemBuffer(header); 275 MemoryBuffer *mainBuf = MemoryBuffer::getMemBuffer(main); 276 SourceMgr.createMainFileIDForMemBuffer(mainBuf); 277 278 const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h", 279 headerBuf->getBufferSize(), 0); 280 SourceMgr.overrideFileContents(headerFile, headerBuf); 281 282 VoidModuleLoader ModLoader; 283 HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts, 284 &*Target); 285 Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(), 286 SourceMgr, HeaderInfo, ModLoader, 287 /*IILookup =*/ 0, 288 /*OwnsHeaderSearch =*/false, 289 /*DelayInitialization =*/ false); 290 291 std::vector<MacroAction> Macros; 292 PP.addPPCallbacks(new MacroTracker(Macros)); 293 294 PP.EnterMainSourceFile(); 295 296 std::vector<Token> toks; 297 while (1) { 298 Token tok; 299 PP.Lex(tok); 300 if (tok.is(tok::eof)) 301 break; 302 toks.push_back(tok); 303 } 304 305 // Make sure we got the tokens that we expected. 306 ASSERT_EQ(0U, toks.size()); 307 308 ASSERT_EQ(9U, Macros.size()); 309 // #define M(x) x 310 ASSERT_TRUE(Macros[0].isDefinition); 311 ASSERT_EQ("M", Macros[0].Name); 312 // #define INC "/test-header.h" 313 ASSERT_TRUE(Macros[1].isDefinition); 314 ASSERT_EQ("INC", Macros[1].Name); 315 // M expansion in #include M(INC) 316 ASSERT_FALSE(Macros[2].isDefinition); 317 ASSERT_EQ("M", Macros[2].Name); 318 // INC expansion in #include M(INC) 319 ASSERT_FALSE(Macros[3].isDefinition); 320 ASSERT_EQ("INC", Macros[3].Name); 321 // #define MACRO_IN_INCLUDE 0 322 ASSERT_TRUE(Macros[4].isDefinition); 323 ASSERT_EQ("MACRO_IN_INCLUDE", Macros[4].Name); 324 // #define INC2 </test-header.h> 325 ASSERT_TRUE(Macros[5].isDefinition); 326 ASSERT_EQ("INC2", Macros[5].Name); 327 // M expansion in #include M(INC2) 328 ASSERT_FALSE(Macros[6].isDefinition); 329 ASSERT_EQ("M", Macros[6].Name); 330 // INC2 expansion in #include M(INC2) 331 ASSERT_FALSE(Macros[7].isDefinition); 332 ASSERT_EQ("INC2", Macros[7].Name); 333 // #define MACRO_IN_INCLUDE 0 334 ASSERT_TRUE(Macros[8].isDefinition); 335 ASSERT_EQ("MACRO_IN_INCLUDE", Macros[8].Name); 336 337 // The INC expansion in #include M(INC) comes before the first 338 // MACRO_IN_INCLUDE definition of the included file. 339 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[3].Loc, Macros[4].Loc)); 340 341 // The INC2 expansion in #include M(INC2) comes before the second 342 // MACRO_IN_INCLUDE definition of the included file. 343 EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[7].Loc, Macros[8].Loc)); 344 } 345 346 #endif 347 348 } // anonymous namespace 349