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