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