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