• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
24 using namespace llvm;
25 using namespace clang;
26 
27 namespace {
28 
29 // The test fixture.
30 class SourceManagerTest : public ::testing::Test {
31 protected:
SourceManagerTest()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 
51 class VoidModuleLoader : public ModuleLoader {
loadModule(SourceLocation ImportLoc,ModuleIdPath Path,Module::NameVisibilityKind Visibility,bool IsInclusionDirective)52   virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
53                              Module::NameVisibilityKind Visibility,
54                              bool IsInclusionDirective) {
55     return 0;
56   }
57 };
58 
TEST_F(SourceManagerTest,isBeforeInTranslationUnit)59 TEST_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 
TEST_F(SourceManagerTest,getColumnNumber)110 TEST_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 
TEST_F(SourceManagerTest,getMacroArgExpandedLocation)160 TEST_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 
227 namespace {
228 
229 struct MacroAction {
230   SourceLocation Loc;
231   std::string Name;
232   bool isDefinition; // if false, it is expansion.
233 
MacroAction__anonf9ec12db0111::__anonf9ec12db0211::MacroAction234   MacroAction(SourceLocation Loc, StringRef Name, bool isDefinition)
235     : Loc(Loc), Name(Name), isDefinition(isDefinition) { }
236 };
237 
238 class MacroTracker : public PPCallbacks {
239   std::vector<MacroAction> &Macros;
240 
241 public:
MacroTracker(std::vector<MacroAction> & Macros)242   explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) { }
243 
MacroDefined(const Token & MacroNameTok,const MacroInfo * MI)244   virtual void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) {
245     Macros.push_back(MacroAction(MI->getDefinitionLoc(),
246                                  MacroNameTok.getIdentifierInfo()->getName(),
247                                  true));
248   }
MacroExpands(const Token & MacroNameTok,const MacroInfo * MI,SourceRange Range)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 
TEST_F(SourceManagerTest,isBeforeInTranslationUnitWithMacroInInclude)259 TEST_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