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
26using namespace clang;
27
28namespace {
29
30// The test fixture.
31class SourceManagerTest : public ::testing::Test {
32protected:
33  SourceManagerTest()
34    : FileMgr(FileMgrOpts),
35      DiagID(new DiagnosticIDs()),
36      Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
37      SourceMgr(Diags, FileMgr),
38      TargetOpts(new TargetOptions) {
39    TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
40    Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
41  }
42
43  FileSystemOptions FileMgrOpts;
44  FileManager FileMgr;
45  IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
46  DiagnosticsEngine Diags;
47  SourceManager SourceMgr;
48  LangOptions LangOpts;
49  std::shared_ptr<TargetOptions> TargetOpts;
50  IntrusiveRefCntPtr<TargetInfo> Target;
51};
52
53class VoidModuleLoader : public ModuleLoader {
54  ModuleLoadResult loadModule(SourceLocation ImportLoc,
55                              ModuleIdPath Path,
56                              Module::NameVisibilityKind Visibility,
57                              bool IsInclusionDirective) override {
58    return ModuleLoadResult();
59  }
60
61  void makeModuleVisible(Module *Mod,
62                         Module::NameVisibilityKind Visibility,
63                         SourceLocation ImportLoc) override { }
64
65  GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc) override
66    { return nullptr; }
67  bool lookupMissingImports(StringRef Name, SourceLocation TriggerLoc) override
68    { return 0; }
69};
70
71TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
72  const char *source =
73    "#define M(x) [x]\n"
74    "M(foo)";
75  std::unique_ptr<llvm::MemoryBuffer> Buf =
76      llvm::MemoryBuffer::getMemBuffer(source);
77  FileID mainFileID = SourceMgr.createFileID(std::move(Buf));
78  SourceMgr.setMainFileID(mainFileID);
79
80  VoidModuleLoader ModLoader;
81  HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts,
82                          &*Target);
83  Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, SourceMgr,
84                  HeaderInfo, ModLoader,
85                  /*IILookup =*/nullptr,
86                  /*OwnsHeaderSearch =*/false);
87  PP.Initialize(*Target);
88  PP.EnterMainSourceFile();
89
90  std::vector<Token> toks;
91  while (1) {
92    Token tok;
93    PP.Lex(tok);
94    if (tok.is(tok::eof))
95      break;
96    toks.push_back(tok);
97  }
98
99  // Make sure we got the tokens that we expected.
100  ASSERT_EQ(3U, toks.size());
101  ASSERT_EQ(tok::l_square, toks[0].getKind());
102  ASSERT_EQ(tok::identifier, toks[1].getKind());
103  ASSERT_EQ(tok::r_square, toks[2].getKind());
104
105  SourceLocation lsqrLoc = toks[0].getLocation();
106  SourceLocation idLoc = toks[1].getLocation();
107  SourceLocation rsqrLoc = toks[2].getLocation();
108
109  SourceLocation macroExpStartLoc = SourceMgr.translateLineCol(mainFileID, 2, 1);
110  SourceLocation macroExpEndLoc = SourceMgr.translateLineCol(mainFileID, 2, 6);
111  ASSERT_TRUE(macroExpStartLoc.isFileID());
112  ASSERT_TRUE(macroExpEndLoc.isFileID());
113
114  SmallString<32> str;
115  ASSERT_EQ("M", PP.getSpelling(macroExpStartLoc, str));
116  ASSERT_EQ(")", PP.getSpelling(macroExpEndLoc, str));
117
118  EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(lsqrLoc, idLoc));
119  EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, rsqrLoc));
120  EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(macroExpStartLoc, idLoc));
121  EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, macroExpEndLoc));
122}
123
124TEST_F(SourceManagerTest, getColumnNumber) {
125  const char *Source =
126    "int x;\n"
127    "int y;";
128
129  std::unique_ptr<llvm::MemoryBuffer> Buf =
130      llvm::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
176TEST_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<llvm::MemoryBuffer> HeaderBuf =
190      llvm::MemoryBuffer::getMemBuffer(header);
191  std::unique_ptr<llvm::MemoryBuffer> MainBuf =
192      llvm::MemoryBuffer::getMemBuffer(main);
193  FileID mainFileID = SourceMgr.createFileID(std::move(MainBuf));
194  SourceMgr.setMainFileID(mainFileID);
195
196  const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h",
197                                                 HeaderBuf->getBufferSize(), 0);
198  SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf));
199
200  VoidModuleLoader ModLoader;
201  HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts,
202                          &*Target);
203  Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, SourceMgr,
204                  HeaderInfo, ModLoader,
205                  /*IILookup =*/nullptr,
206                  /*OwnsHeaderSearch =*/false);
207  PP.Initialize(*Target);
208  PP.EnterMainSourceFile();
209
210  std::vector<Token> toks;
211  while (1) {
212    Token tok;
213    PP.Lex(tok);
214    if (tok.is(tok::eof))
215      break;
216    toks.push_back(tok);
217  }
218
219  // Make sure we got the tokens that we expected.
220  ASSERT_EQ(4U, toks.size());
221  ASSERT_EQ(tok::numeric_constant, toks[0].getKind());
222  ASSERT_EQ(tok::numeric_constant, toks[1].getKind());
223  ASSERT_EQ(tok::numeric_constant, toks[2].getKind());
224  ASSERT_EQ(tok::numeric_constant, toks[3].getKind());
225
226  SourceLocation defLoc = SourceMgr.translateLineCol(mainFileID, 2, 13);
227  SourceLocation loc1 = SourceMgr.translateLineCol(mainFileID, 3, 8);
228  SourceLocation loc2 = SourceMgr.translateLineCol(mainFileID, 4, 4);
229  SourceLocation loc3 = SourceMgr.translateLineCol(mainFileID, 5, 7);
230  SourceLocation defLoc2 = SourceMgr.translateLineCol(mainFileID, 6, 22);
231  defLoc = SourceMgr.getMacroArgExpandedLocation(defLoc);
232  loc1 = SourceMgr.getMacroArgExpandedLocation(loc1);
233  loc2 = SourceMgr.getMacroArgExpandedLocation(loc2);
234  loc3 = SourceMgr.getMacroArgExpandedLocation(loc3);
235  defLoc2 = SourceMgr.getMacroArgExpandedLocation(defLoc2);
236
237  EXPECT_TRUE(defLoc.isFileID());
238  EXPECT_TRUE(loc1.isFileID());
239  EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc2));
240  EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc3));
241  EXPECT_EQ(loc2, toks[1].getLocation());
242  EXPECT_EQ(loc3, toks[2].getLocation());
243  EXPECT_TRUE(defLoc2.isFileID());
244}
245
246namespace {
247
248struct MacroAction {
249  SourceLocation Loc;
250  std::string Name;
251  bool isDefinition; // if false, it is expansion.
252
253  MacroAction(SourceLocation Loc, StringRef Name, bool isDefinition)
254    : Loc(Loc), Name(Name), isDefinition(isDefinition) { }
255};
256
257class MacroTracker : public PPCallbacks {
258  std::vector<MacroAction> &Macros;
259
260public:
261  explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) { }
262
263  void MacroDefined(const Token &MacroNameTok,
264                    const MacroDirective *MD) override {
265    Macros.push_back(MacroAction(MD->getLocation(),
266                                 MacroNameTok.getIdentifierInfo()->getName(),
267                                 true));
268  }
269  void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
270                    SourceRange Range, const MacroArgs *Args) override {
271    Macros.push_back(MacroAction(MacroNameTok.getLocation(),
272                                 MacroNameTok.getIdentifierInfo()->getName(),
273                                 false));
274  }
275};
276
277}
278
279TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
280  const char *header =
281    "#define MACRO_IN_INCLUDE 0\n";
282
283  const char *main =
284    "#define M(x) x\n"
285    "#define INC \"/test-header.h\"\n"
286    "#include M(INC)\n"
287    "#define INC2 </test-header.h>\n"
288    "#include M(INC2)\n";
289
290  std::unique_ptr<llvm::MemoryBuffer> HeaderBuf =
291      llvm::MemoryBuffer::getMemBuffer(header);
292  std::unique_ptr<llvm::MemoryBuffer> MainBuf =
293      llvm::MemoryBuffer::getMemBuffer(main);
294  SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(MainBuf)));
295
296  const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h",
297                                                 HeaderBuf->getBufferSize(), 0);
298  SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf));
299
300  VoidModuleLoader ModLoader;
301  HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts,
302                          &*Target);
303  Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, SourceMgr,
304                  HeaderInfo, ModLoader,
305                  /*IILookup =*/nullptr,
306                  /*OwnsHeaderSearch =*/false);
307  PP.Initialize(*Target);
308
309  std::vector<MacroAction> Macros;
310  PP.addPPCallbacks(llvm::make_unique<MacroTracker>(Macros));
311
312  PP.EnterMainSourceFile();
313
314  std::vector<Token> toks;
315  while (1) {
316    Token tok;
317    PP.Lex(tok);
318    if (tok.is(tok::eof))
319      break;
320    toks.push_back(tok);
321  }
322
323  // Make sure we got the tokens that we expected.
324  ASSERT_EQ(0U, toks.size());
325
326  ASSERT_EQ(9U, Macros.size());
327  // #define M(x) x
328  ASSERT_TRUE(Macros[0].isDefinition);
329  ASSERT_EQ("M", Macros[0].Name);
330  // #define INC "/test-header.h"
331  ASSERT_TRUE(Macros[1].isDefinition);
332  ASSERT_EQ("INC", Macros[1].Name);
333  // M expansion in #include M(INC)
334  ASSERT_FALSE(Macros[2].isDefinition);
335  ASSERT_EQ("M", Macros[2].Name);
336  // INC expansion in #include M(INC)
337  ASSERT_FALSE(Macros[3].isDefinition);
338  ASSERT_EQ("INC", Macros[3].Name);
339  // #define MACRO_IN_INCLUDE 0
340  ASSERT_TRUE(Macros[4].isDefinition);
341  ASSERT_EQ("MACRO_IN_INCLUDE", Macros[4].Name);
342  // #define INC2 </test-header.h>
343  ASSERT_TRUE(Macros[5].isDefinition);
344  ASSERT_EQ("INC2", Macros[5].Name);
345  // M expansion in #include M(INC2)
346  ASSERT_FALSE(Macros[6].isDefinition);
347  ASSERT_EQ("M", Macros[6].Name);
348  // INC2 expansion in #include M(INC2)
349  ASSERT_FALSE(Macros[7].isDefinition);
350  ASSERT_EQ("INC2", Macros[7].Name);
351  // #define MACRO_IN_INCLUDE 0
352  ASSERT_TRUE(Macros[8].isDefinition);
353  ASSERT_EQ("MACRO_IN_INCLUDE", Macros[8].Name);
354
355  // The INC expansion in #include M(INC) comes before the first
356  // MACRO_IN_INCLUDE definition of the included file.
357  EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[3].Loc, Macros[4].Loc));
358
359  // The INC2 expansion in #include M(INC2) comes before the second
360  // MACRO_IN_INCLUDE definition of the included file.
361  EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[7].Loc, Macros[8].Loc));
362}
363
364#endif
365
366} // anonymous namespace
367