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