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