1 //===- unittests/Basic/SourceManagerTest.cpp ------ SourceManager tests ---===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "clang/Basic/SourceManager.h"
10 #include "clang/Basic/Diagnostic.h"
11 #include "clang/Basic/DiagnosticOptions.h"
12 #include "clang/Basic/FileManager.h"
13 #include "clang/Basic/LangOptions.h"
14 #include "clang/Basic/TargetInfo.h"
15 #include "clang/Basic/TargetOptions.h"
16 #include "clang/Lex/HeaderSearch.h"
17 #include "clang/Lex/HeaderSearchOptions.h"
18 #include "clang/Lex/ModuleLoader.h"
19 #include "clang/Lex/Preprocessor.h"
20 #include "clang/Lex/PreprocessorOptions.h"
21 #include "llvm/ADT/SmallString.h"
22 #include "llvm/Config/llvm-config.h"
23 #include "gtest/gtest.h"
24 
25 using namespace clang;
26 
27 namespace {
28 
29 // The test fixture.
30 class SourceManagerTest : public ::testing::Test {
31 protected:
32   SourceManagerTest()
33     : FileMgr(FileMgrOpts),
34       DiagID(new DiagnosticIDs()),
35       Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
36       SourceMgr(Diags, FileMgr),
37       TargetOpts(new TargetOptions) {
38     TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
39     Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
40   }
41 
42   FileSystemOptions FileMgrOpts;
43   FileManager FileMgr;
44   IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
45   DiagnosticsEngine Diags;
46   SourceManager SourceMgr;
47   LangOptions LangOpts;
48   std::shared_ptr<TargetOptions> TargetOpts;
49   IntrusiveRefCntPtr<TargetInfo> Target;
50 };
51 
52 TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
53   const char *source =
54     "#define M(x) [x]\n"
55     "M(foo)";
56   std::unique_ptr<llvm::MemoryBuffer> Buf =
57       llvm::MemoryBuffer::getMemBuffer(source);
58   FileID mainFileID = SourceMgr.createFileID(std::move(Buf));
59   SourceMgr.setMainFileID(mainFileID);
60 
61   TrivialModuleLoader ModLoader;
62   HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
63                           Diags, LangOpts, &*Target);
64   Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
65                   SourceMgr, HeaderInfo, ModLoader,
66                   /*IILookup =*/nullptr,
67                   /*OwnsHeaderSearch =*/false);
68   PP.Initialize(*Target);
69   PP.EnterMainSourceFile();
70 
71   std::vector<Token> toks;
72   while (1) {
73     Token tok;
74     PP.Lex(tok);
75     if (tok.is(tok::eof))
76       break;
77     toks.push_back(tok);
78   }
79 
80   // Make sure we got the tokens that we expected.
81   ASSERT_EQ(3U, toks.size());
82   ASSERT_EQ(tok::l_square, toks[0].getKind());
83   ASSERT_EQ(tok::identifier, toks[1].getKind());
84   ASSERT_EQ(tok::r_square, toks[2].getKind());
85 
86   SourceLocation lsqrLoc = toks[0].getLocation();
87   SourceLocation idLoc = toks[1].getLocation();
88   SourceLocation rsqrLoc = toks[2].getLocation();
89 
90   SourceLocation macroExpStartLoc = SourceMgr.translateLineCol(mainFileID, 2, 1);
91   SourceLocation macroExpEndLoc = SourceMgr.translateLineCol(mainFileID, 2, 6);
92   ASSERT_TRUE(macroExpStartLoc.isFileID());
93   ASSERT_TRUE(macroExpEndLoc.isFileID());
94 
95   SmallString<32> str;
96   ASSERT_EQ("M", PP.getSpelling(macroExpStartLoc, str));
97   ASSERT_EQ(")", PP.getSpelling(macroExpEndLoc, str));
98 
99   EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(lsqrLoc, idLoc));
100   EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, rsqrLoc));
101   EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(macroExpStartLoc, idLoc));
102   EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(idLoc, macroExpEndLoc));
103 }
104 
105 TEST_F(SourceManagerTest, getColumnNumber) {
106   const char *Source =
107     "int x;\n"
108     "int y;";
109 
110   std::unique_ptr<llvm::MemoryBuffer> Buf =
111       llvm::MemoryBuffer::getMemBuffer(Source);
112   FileID MainFileID = SourceMgr.createFileID(std::move(Buf));
113   SourceMgr.setMainFileID(MainFileID);
114 
115   bool Invalid;
116 
117   Invalid = false;
118   EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 0, &Invalid));
119   EXPECT_TRUE(!Invalid);
120 
121   Invalid = false;
122   EXPECT_EQ(5U, SourceMgr.getColumnNumber(MainFileID, 4, &Invalid));
123   EXPECT_TRUE(!Invalid);
124 
125   Invalid = false;
126   EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 7, &Invalid));
127   EXPECT_TRUE(!Invalid);
128 
129   Invalid = false;
130   EXPECT_EQ(5U, SourceMgr.getColumnNumber(MainFileID, 11, &Invalid));
131   EXPECT_TRUE(!Invalid);
132 
133   Invalid = false;
134   EXPECT_EQ(7U, SourceMgr.getColumnNumber(MainFileID, strlen(Source),
135                                          &Invalid));
136   EXPECT_TRUE(!Invalid);
137 
138   Invalid = false;
139   SourceMgr.getColumnNumber(MainFileID, strlen(Source)+1, &Invalid);
140   EXPECT_TRUE(Invalid);
141 
142   // Test invalid files
143   Invalid = false;
144   SourceMgr.getColumnNumber(FileID(), 0, &Invalid);
145   EXPECT_TRUE(Invalid);
146 
147   Invalid = false;
148   SourceMgr.getColumnNumber(FileID(), 1, &Invalid);
149   EXPECT_TRUE(Invalid);
150 
151   // Test with no invalid flag.
152   EXPECT_EQ(1U, SourceMgr.getColumnNumber(MainFileID, 0, nullptr));
153 }
154 
155 TEST_F(SourceManagerTest, locationPrintTest) {
156   const char *header = "#define IDENTITY(x) x\n";
157 
158   const char *Source = "int x;\n"
159                        "include \"test-header.h\"\n"
160                        "IDENTITY(int y);\n"
161                        "int z;";
162 
163   std::unique_ptr<llvm::MemoryBuffer> HeaderBuf =
164       llvm::MemoryBuffer::getMemBuffer(header);
165   std::unique_ptr<llvm::MemoryBuffer> Buf =
166       llvm::MemoryBuffer::getMemBuffer(Source);
167 
168   const FileEntry *SourceFile =
169       FileMgr.getVirtualFile("/mainFile.cpp", Buf->getBufferSize(), 0);
170   SourceMgr.overrideFileContents(SourceFile, std::move(Buf));
171 
172   const FileEntry *HeaderFile =
173       FileMgr.getVirtualFile("/test-header.h", HeaderBuf->getBufferSize(), 0);
174   SourceMgr.overrideFileContents(HeaderFile, std::move(HeaderBuf));
175 
176   FileID MainFileID = SourceMgr.getOrCreateFileID(SourceFile, SrcMgr::C_User);
177   FileID HeaderFileID = SourceMgr.getOrCreateFileID(HeaderFile, SrcMgr::C_User);
178   SourceMgr.setMainFileID(MainFileID);
179 
180   auto BeginLoc = SourceMgr.getLocForStartOfFile(MainFileID);
181   auto EndLoc = SourceMgr.getLocForEndOfFile(MainFileID);
182 
183   auto BeginEOLLoc = SourceMgr.translateLineCol(MainFileID, 1, 7);
184 
185   auto HeaderLoc = SourceMgr.getLocForStartOfFile(HeaderFileID);
186 
187   EXPECT_EQ(BeginLoc.printToString(SourceMgr), "/mainFile.cpp:1:1");
188   EXPECT_EQ(EndLoc.printToString(SourceMgr), "/mainFile.cpp:4:7");
189 
190   EXPECT_EQ(BeginEOLLoc.printToString(SourceMgr), "/mainFile.cpp:1:7");
191   EXPECT_EQ(HeaderLoc.printToString(SourceMgr), "/test-header.h:1:1");
192 
193   EXPECT_EQ(SourceRange(BeginLoc, BeginLoc).printToString(SourceMgr),
194             "</mainFile.cpp:1:1>");
195   EXPECT_EQ(SourceRange(BeginLoc, BeginEOLLoc).printToString(SourceMgr),
196             "</mainFile.cpp:1:1, col:7>");
197   EXPECT_EQ(SourceRange(BeginLoc, EndLoc).printToString(SourceMgr),
198             "</mainFile.cpp:1:1, line:4:7>");
199   EXPECT_EQ(SourceRange(BeginLoc, HeaderLoc).printToString(SourceMgr),
200             "</mainFile.cpp:1:1, /test-header.h:1:1>");
201 }
202 
203 #if defined(LLVM_ON_UNIX)
204 
205 TEST_F(SourceManagerTest, getMacroArgExpandedLocation) {
206   const char *header =
207     "#define FM(x,y) x\n";
208 
209   const char *main =
210     "#include \"/test-header.h\"\n"
211     "#define VAL 0\n"
212     "FM(VAL,0)\n"
213     "FM(0,VAL)\n"
214     "FM(FM(0,VAL),0)\n"
215     "#define CONCAT(X, Y) X##Y\n"
216     "CONCAT(1,1)\n";
217 
218   std::unique_ptr<llvm::MemoryBuffer> HeaderBuf =
219       llvm::MemoryBuffer::getMemBuffer(header);
220   std::unique_ptr<llvm::MemoryBuffer> MainBuf =
221       llvm::MemoryBuffer::getMemBuffer(main);
222   FileID mainFileID = SourceMgr.createFileID(std::move(MainBuf));
223   SourceMgr.setMainFileID(mainFileID);
224 
225   const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h",
226                                                  HeaderBuf->getBufferSize(), 0);
227   SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf));
228 
229   TrivialModuleLoader ModLoader;
230   HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
231                           Diags, LangOpts, &*Target);
232   Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
233                   SourceMgr, HeaderInfo, ModLoader,
234                   /*IILookup =*/nullptr,
235                   /*OwnsHeaderSearch =*/false);
236   PP.Initialize(*Target);
237   PP.EnterMainSourceFile();
238 
239   std::vector<Token> toks;
240   while (1) {
241     Token tok;
242     PP.Lex(tok);
243     if (tok.is(tok::eof))
244       break;
245     toks.push_back(tok);
246   }
247 
248   // Make sure we got the tokens that we expected.
249   ASSERT_EQ(4U, toks.size());
250   ASSERT_EQ(tok::numeric_constant, toks[0].getKind());
251   ASSERT_EQ(tok::numeric_constant, toks[1].getKind());
252   ASSERT_EQ(tok::numeric_constant, toks[2].getKind());
253   ASSERT_EQ(tok::numeric_constant, toks[3].getKind());
254 
255   SourceLocation defLoc = SourceMgr.translateLineCol(mainFileID, 2, 13);
256   SourceLocation loc1 = SourceMgr.translateLineCol(mainFileID, 3, 8);
257   SourceLocation loc2 = SourceMgr.translateLineCol(mainFileID, 4, 4);
258   SourceLocation loc3 = SourceMgr.translateLineCol(mainFileID, 5, 7);
259   SourceLocation defLoc2 = SourceMgr.translateLineCol(mainFileID, 6, 22);
260   defLoc = SourceMgr.getMacroArgExpandedLocation(defLoc);
261   loc1 = SourceMgr.getMacroArgExpandedLocation(loc1);
262   loc2 = SourceMgr.getMacroArgExpandedLocation(loc2);
263   loc3 = SourceMgr.getMacroArgExpandedLocation(loc3);
264   defLoc2 = SourceMgr.getMacroArgExpandedLocation(defLoc2);
265 
266   EXPECT_TRUE(defLoc.isFileID());
267   EXPECT_TRUE(loc1.isFileID());
268   EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc2));
269   EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc3));
270   EXPECT_EQ(loc2, toks[1].getLocation());
271   EXPECT_EQ(loc3, toks[2].getLocation());
272   EXPECT_TRUE(defLoc2.isFileID());
273 }
274 
275 namespace {
276 
277 struct MacroAction {
278   enum Kind { kExpansion, kDefinition, kUnDefinition};
279 
280   SourceLocation Loc;
281   std::string Name;
282   unsigned MAKind : 3;
283 
284   MacroAction(SourceLocation Loc, StringRef Name, unsigned K)
285     : Loc(Loc), Name(Name), MAKind(K) { }
286 
287   bool isExpansion() const { return MAKind == kExpansion; }
288   bool isDefinition() const { return MAKind & kDefinition; }
289   bool isUnDefinition() const { return MAKind & kUnDefinition; }
290 };
291 
292 class MacroTracker : public PPCallbacks {
293   std::vector<MacroAction> &Macros;
294 
295 public:
296   explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) { }
297 
298   void MacroDefined(const Token &MacroNameTok,
299                     const MacroDirective *MD) override {
300     Macros.push_back(MacroAction(MD->getLocation(),
301                                  MacroNameTok.getIdentifierInfo()->getName(),
302                                  MacroAction::kDefinition));
303   }
304   void MacroUndefined(const Token &MacroNameTok,
305                       const MacroDefinition &MD,
306                       const MacroDirective  *UD) override {
307     Macros.push_back(
308         MacroAction(UD ? UD->getLocation() : SourceLocation(),
309                     MacroNameTok.getIdentifierInfo()->getName(),
310                     UD ? MacroAction::kDefinition | MacroAction::kUnDefinition
311                        : MacroAction::kUnDefinition));
312   }
313   void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
314                     SourceRange Range, const MacroArgs *Args) override {
315     Macros.push_back(MacroAction(MacroNameTok.getLocation(),
316                                  MacroNameTok.getIdentifierInfo()->getName(),
317                                  MacroAction::kExpansion));
318   }
319 };
320 
321 }
322 
323 TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
324   const char *header =
325     "#define MACRO_IN_INCLUDE 0\n"
326     "#define MACRO_DEFINED\n"
327     "#undef MACRO_DEFINED\n"
328     "#undef MACRO_UNDEFINED\n";
329 
330   const char *main =
331     "#define M(x) x\n"
332     "#define INC \"/test-header.h\"\n"
333     "#include M(INC)\n"
334     "#define INC2 </test-header.h>\n"
335     "#include M(INC2)\n";
336 
337   std::unique_ptr<llvm::MemoryBuffer> HeaderBuf =
338       llvm::MemoryBuffer::getMemBuffer(header);
339   std::unique_ptr<llvm::MemoryBuffer> MainBuf =
340       llvm::MemoryBuffer::getMemBuffer(main);
341   SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(MainBuf)));
342 
343   const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h",
344                                                  HeaderBuf->getBufferSize(), 0);
345   SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf));
346 
347   TrivialModuleLoader ModLoader;
348   HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
349                           Diags, LangOpts, &*Target);
350   Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
351                   SourceMgr, HeaderInfo, ModLoader,
352                   /*IILookup =*/nullptr,
353                   /*OwnsHeaderSearch =*/false);
354   PP.Initialize(*Target);
355 
356   std::vector<MacroAction> Macros;
357   PP.addPPCallbacks(llvm::make_unique<MacroTracker>(Macros));
358 
359   PP.EnterMainSourceFile();
360 
361   std::vector<Token> toks;
362   while (1) {
363     Token tok;
364     PP.Lex(tok);
365     if (tok.is(tok::eof))
366       break;
367     toks.push_back(tok);
368   }
369 
370   // Make sure we got the tokens that we expected.
371   ASSERT_EQ(0U, toks.size());
372 
373   ASSERT_EQ(15U, Macros.size());
374   // #define M(x) x
375   ASSERT_TRUE(Macros[0].isDefinition());
376   ASSERT_EQ("M", Macros[0].Name);
377   // #define INC "/test-header.h"
378   ASSERT_TRUE(Macros[1].isDefinition());
379   ASSERT_EQ("INC", Macros[1].Name);
380   // M expansion in #include M(INC)
381   ASSERT_FALSE(Macros[2].isDefinition());
382   ASSERT_EQ("M", Macros[2].Name);
383   // INC expansion in #include M(INC)
384   ASSERT_TRUE(Macros[3].isExpansion());
385   ASSERT_EQ("INC", Macros[3].Name);
386   // #define MACRO_IN_INCLUDE 0
387   ASSERT_TRUE(Macros[4].isDefinition());
388   ASSERT_EQ("MACRO_IN_INCLUDE", Macros[4].Name);
389   // #define MACRO_DEFINED
390   ASSERT_TRUE(Macros[5].isDefinition());
391   ASSERT_FALSE(Macros[5].isUnDefinition());
392   ASSERT_EQ("MACRO_DEFINED", Macros[5].Name);
393   // #undef MACRO_DEFINED
394   ASSERT_TRUE(Macros[6].isDefinition());
395   ASSERT_TRUE(Macros[6].isUnDefinition());
396   ASSERT_EQ("MACRO_DEFINED", Macros[6].Name);
397   // #undef MACRO_UNDEFINED
398   ASSERT_FALSE(Macros[7].isDefinition());
399   ASSERT_TRUE(Macros[7].isUnDefinition());
400   ASSERT_EQ("MACRO_UNDEFINED", Macros[7].Name);
401   // #define INC2 </test-header.h>
402   ASSERT_TRUE(Macros[8].isDefinition());
403   ASSERT_EQ("INC2", Macros[8].Name);
404   // M expansion in #include M(INC2)
405   ASSERT_FALSE(Macros[9].isDefinition());
406   ASSERT_EQ("M", Macros[9].Name);
407   // INC2 expansion in #include M(INC2)
408   ASSERT_TRUE(Macros[10].isExpansion());
409   ASSERT_EQ("INC2", Macros[10].Name);
410   // #define MACRO_IN_INCLUDE 0
411   ASSERT_TRUE(Macros[11].isDefinition());
412   ASSERT_EQ("MACRO_IN_INCLUDE", Macros[11].Name);
413 
414   // The INC expansion in #include M(INC) comes before the first
415   // MACRO_IN_INCLUDE definition of the included file.
416   EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[3].Loc, Macros[4].Loc));
417 
418   // The INC2 expansion in #include M(INC2) comes before the second
419   // MACRO_IN_INCLUDE definition of the included file.
420   EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[10].Loc, Macros[11].Loc));
421 }
422 
423 #endif
424 
425 } // anonymous namespace
426