xref: /llvm-project/clang/unittests/Basic/SourceManagerTest.cpp (revision 5d2ed489870cb4b093ec8f52ab4a4ef81428d6fe)
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 TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
55   const char *source =
56     "#define M(x) [x]\n"
57     "M(foo)";
58   std::unique_ptr<llvm::MemoryBuffer> Buf =
59       llvm::MemoryBuffer::getMemBuffer(source);
60   FileID mainFileID = SourceMgr.createFileID(std::move(Buf));
61   SourceMgr.setMainFileID(mainFileID);
62 
63   TrivialModuleLoader ModLoader;
64   MemoryBufferCache PCMCache;
65   HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
66                           Diags, LangOpts, &*Target);
67   Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
68                   SourceMgr, PCMCache, HeaderInfo, ModLoader,
69                   /*IILookup =*/nullptr,
70                   /*OwnsHeaderSearch =*/false);
71   PP.Initialize(*Target);
72   PP.EnterMainSourceFile();
73 
74   std::vector<Token> toks;
75   while (1) {
76     Token tok;
77     PP.Lex(tok);
78     if (tok.is(tok::eof))
79       break;
80     toks.push_back(tok);
81   }
82 
83   // Make sure we got the tokens that we expected.
84   ASSERT_EQ(3U, toks.size());
85   ASSERT_EQ(tok::l_square, toks[0].getKind());
86   ASSERT_EQ(tok::identifier, toks[1].getKind());
87   ASSERT_EQ(tok::r_square, toks[2].getKind());
88 
89   SourceLocation lsqrLoc = toks[0].getLocation();
90   SourceLocation idLoc = toks[1].getLocation();
91   SourceLocation rsqrLoc = toks[2].getLocation();
92 
93   SourceLocation macroExpStartLoc = SourceMgr.translateLineCol(mainFileID, 2, 1);
94   SourceLocation macroExpEndLoc = SourceMgr.translateLineCol(mainFileID, 2, 6);
95   ASSERT_TRUE(macroExpStartLoc.isFileID());
96   ASSERT_TRUE(macroExpEndLoc.isFileID());
97 
98   SmallString<32> str;
99   ASSERT_EQ("M", PP.getSpelling(macroExpStartLoc, str));
100   ASSERT_EQ(")", PP.getSpelling(macroExpEndLoc, str));
101 
102   EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(lsqrLoc, idLoc));
103   EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, rsqrLoc));
104   EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(macroExpStartLoc, idLoc));
105   EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, macroExpEndLoc));
106 }
107 
108 TEST_F(SourceManagerTest, getColumnNumber) {
109   const char *Source =
110     "int x;\n"
111     "int y;";
112 
113   std::unique_ptr<llvm::MemoryBuffer> Buf =
114       llvm::MemoryBuffer::getMemBuffer(Source);
115   FileID MainFileID = SourceMgr.createFileID(std::move(Buf));
116   SourceMgr.setMainFileID(MainFileID);
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, nullptr));
156 }
157 
158 #if defined(LLVM_ON_UNIX)
159 
160 TEST_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   std::unique_ptr<llvm::MemoryBuffer> HeaderBuf =
174       llvm::MemoryBuffer::getMemBuffer(header);
175   std::unique_ptr<llvm::MemoryBuffer> MainBuf =
176       llvm::MemoryBuffer::getMemBuffer(main);
177   FileID mainFileID = SourceMgr.createFileID(std::move(MainBuf));
178   SourceMgr.setMainFileID(mainFileID);
179 
180   const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h",
181                                                  HeaderBuf->getBufferSize(), 0);
182   SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf));
183 
184   TrivialModuleLoader ModLoader;
185   MemoryBufferCache PCMCache;
186   HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
187                           Diags, LangOpts, &*Target);
188   Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
189                   SourceMgr, PCMCache, HeaderInfo, ModLoader,
190                   /*IILookup =*/nullptr,
191                   /*OwnsHeaderSearch =*/false);
192   PP.Initialize(*Target);
193   PP.EnterMainSourceFile();
194 
195   std::vector<Token> toks;
196   while (1) {
197     Token tok;
198     PP.Lex(tok);
199     if (tok.is(tok::eof))
200       break;
201     toks.push_back(tok);
202   }
203 
204   // Make sure we got the tokens that we expected.
205   ASSERT_EQ(4U, toks.size());
206   ASSERT_EQ(tok::numeric_constant, toks[0].getKind());
207   ASSERT_EQ(tok::numeric_constant, toks[1].getKind());
208   ASSERT_EQ(tok::numeric_constant, toks[2].getKind());
209   ASSERT_EQ(tok::numeric_constant, toks[3].getKind());
210 
211   SourceLocation defLoc = SourceMgr.translateLineCol(mainFileID, 2, 13);
212   SourceLocation loc1 = SourceMgr.translateLineCol(mainFileID, 3, 8);
213   SourceLocation loc2 = SourceMgr.translateLineCol(mainFileID, 4, 4);
214   SourceLocation loc3 = SourceMgr.translateLineCol(mainFileID, 5, 7);
215   SourceLocation defLoc2 = SourceMgr.translateLineCol(mainFileID, 6, 22);
216   defLoc = SourceMgr.getMacroArgExpandedLocation(defLoc);
217   loc1 = SourceMgr.getMacroArgExpandedLocation(loc1);
218   loc2 = SourceMgr.getMacroArgExpandedLocation(loc2);
219   loc3 = SourceMgr.getMacroArgExpandedLocation(loc3);
220   defLoc2 = SourceMgr.getMacroArgExpandedLocation(defLoc2);
221 
222   EXPECT_TRUE(defLoc.isFileID());
223   EXPECT_TRUE(loc1.isFileID());
224   EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc2));
225   EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc3));
226   EXPECT_EQ(loc2, toks[1].getLocation());
227   EXPECT_EQ(loc3, toks[2].getLocation());
228   EXPECT_TRUE(defLoc2.isFileID());
229 }
230 
231 namespace {
232 
233 struct MacroAction {
234   enum Kind { kExpansion, kDefinition, kUnDefinition};
235 
236   SourceLocation Loc;
237   std::string Name;
238   unsigned MAKind : 3;
239 
240   MacroAction(SourceLocation Loc, StringRef Name, unsigned K)
241     : Loc(Loc), Name(Name), MAKind(K) { }
242 
243   bool isExpansion() const { return MAKind == kExpansion; }
244   bool isDefinition() const { return MAKind & kDefinition; }
245   bool isUnDefinition() const { return MAKind & kUnDefinition; }
246 };
247 
248 class MacroTracker : public PPCallbacks {
249   std::vector<MacroAction> &Macros;
250 
251 public:
252   explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) { }
253 
254   void MacroDefined(const Token &MacroNameTok,
255                     const MacroDirective *MD) override {
256     Macros.push_back(MacroAction(MD->getLocation(),
257                                  MacroNameTok.getIdentifierInfo()->getName(),
258                                  MacroAction::kDefinition));
259   }
260   void MacroUndefined(const Token &MacroNameTok,
261                       const MacroDefinition &MD,
262                       const MacroDirective  *UD) override {
263     Macros.push_back(
264         MacroAction(UD ? UD->getLocation() : SourceLocation(),
265                     MacroNameTok.getIdentifierInfo()->getName(),
266                     UD ? MacroAction::kDefinition | MacroAction::kUnDefinition
267                        : MacroAction::kUnDefinition));
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                                  MacroAction::kExpansion));
274   }
275 };
276 
277 }
278 
279 TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
280   const char *header =
281     "#define MACRO_IN_INCLUDE 0\n"
282     "#define MACRO_DEFINED\n"
283     "#undef MACRO_DEFINED\n"
284     "#undef MACRO_UNDEFINED\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   TrivialModuleLoader 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(15U, 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_TRUE(Macros[3].isExpansion());
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 MACRO_DEFINED
347   ASSERT_TRUE(Macros[5].isDefinition());
348   ASSERT_FALSE(Macros[5].isUnDefinition());
349   ASSERT_EQ("MACRO_DEFINED", Macros[5].Name);
350   // #undef MACRO_DEFINED
351   ASSERT_TRUE(Macros[6].isDefinition());
352   ASSERT_TRUE(Macros[6].isUnDefinition());
353   ASSERT_EQ("MACRO_DEFINED", Macros[6].Name);
354   // #undef MACRO_UNDEFINED
355   ASSERT_FALSE(Macros[7].isDefinition());
356   ASSERT_TRUE(Macros[7].isUnDefinition());
357   ASSERT_EQ("MACRO_UNDEFINED", Macros[7].Name);
358   // #define INC2 </test-header.h>
359   ASSERT_TRUE(Macros[8].isDefinition());
360   ASSERT_EQ("INC2", Macros[8].Name);
361   // M expansion in #include M(INC2)
362   ASSERT_FALSE(Macros[9].isDefinition());
363   ASSERT_EQ("M", Macros[9].Name);
364   // INC2 expansion in #include M(INC2)
365   ASSERT_TRUE(Macros[10].isExpansion());
366   ASSERT_EQ("INC2", Macros[10].Name);
367   // #define MACRO_IN_INCLUDE 0
368   ASSERT_TRUE(Macros[11].isDefinition());
369   ASSERT_EQ("MACRO_IN_INCLUDE", Macros[11].Name);
370 
371   // The INC expansion in #include M(INC) comes before the first
372   // MACRO_IN_INCLUDE definition of the included file.
373   EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[3].Loc, Macros[4].Loc));
374 
375   // The INC2 expansion in #include M(INC2) comes before the second
376   // MACRO_IN_INCLUDE definition of the included file.
377   EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[10].Loc, Macros[11].Loc));
378 }
379 
380 #endif
381 
382 } // anonymous namespace
383