xref: /llvm-project/clang/unittests/Basic/SourceManagerTest.cpp (revision b8e08860065a64963f49da64742350a8231b1727)
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 TEST_F(SourceManagerTest, locationPrintTest) {
159   const char *header = "#define IDENTITY(x) x\n";
160 
161   const char *Source = "int x;\n"
162                        "include \"test-header.h\"\n"
163                        "IDENTITY(int y);\n"
164                        "int z;";
165 
166   std::unique_ptr<llvm::MemoryBuffer> HeaderBuf =
167       llvm::MemoryBuffer::getMemBuffer(header);
168   std::unique_ptr<llvm::MemoryBuffer> Buf =
169       llvm::MemoryBuffer::getMemBuffer(Source);
170 
171   const FileEntry *SourceFile =
172       FileMgr.getVirtualFile("/mainFile.cpp", Buf->getBufferSize(), 0);
173   SourceMgr.overrideFileContents(SourceFile, std::move(Buf));
174 
175   const FileEntry *HeaderFile =
176       FileMgr.getVirtualFile("/test-header.h", HeaderBuf->getBufferSize(), 0);
177   SourceMgr.overrideFileContents(HeaderFile, std::move(HeaderBuf));
178 
179   FileID MainFileID = SourceMgr.getOrCreateFileID(SourceFile, SrcMgr::C_User);
180   FileID HeaderFileID = SourceMgr.getOrCreateFileID(HeaderFile, SrcMgr::C_User);
181   SourceMgr.setMainFileID(MainFileID);
182 
183   auto BeginLoc = SourceMgr.getLocForStartOfFile(MainFileID);
184   auto EndLoc = SourceMgr.getLocForEndOfFile(MainFileID);
185 
186   auto BeginEOLLoc = SourceMgr.translateLineCol(MainFileID, 1, 7);
187 
188   auto HeaderLoc = SourceMgr.getLocForStartOfFile(HeaderFileID);
189 
190   EXPECT_EQ(BeginLoc.printToString(SourceMgr), "/mainFile.cpp:1:1");
191   EXPECT_EQ(EndLoc.printToString(SourceMgr), "/mainFile.cpp:4:7");
192 
193   EXPECT_EQ(BeginEOLLoc.printToString(SourceMgr), "/mainFile.cpp:1:7");
194   EXPECT_EQ(HeaderLoc.printToString(SourceMgr), "/test-header.h:1:1");
195 
196   EXPECT_EQ(SourceRange(BeginLoc, BeginLoc).printToString(SourceMgr),
197             "</mainFile.cpp:1:1>");
198   EXPECT_EQ(SourceRange(BeginLoc, BeginEOLLoc).printToString(SourceMgr),
199             "</mainFile.cpp:1:1, col:7>");
200   EXPECT_EQ(SourceRange(BeginLoc, EndLoc).printToString(SourceMgr),
201             "</mainFile.cpp:1:1, line:4:7>");
202   EXPECT_EQ(SourceRange(BeginLoc, HeaderLoc).printToString(SourceMgr),
203             "</mainFile.cpp:1:1, /test-header.h:1:1>");
204 }
205 
206 #if defined(LLVM_ON_UNIX)
207 
208 TEST_F(SourceManagerTest, getMacroArgExpandedLocation) {
209   const char *header =
210     "#define FM(x,y) x\n";
211 
212   const char *main =
213     "#include \"/test-header.h\"\n"
214     "#define VAL 0\n"
215     "FM(VAL,0)\n"
216     "FM(0,VAL)\n"
217     "FM(FM(0,VAL),0)\n"
218     "#define CONCAT(X, Y) X##Y\n"
219     "CONCAT(1,1)\n";
220 
221   std::unique_ptr<llvm::MemoryBuffer> HeaderBuf =
222       llvm::MemoryBuffer::getMemBuffer(header);
223   std::unique_ptr<llvm::MemoryBuffer> MainBuf =
224       llvm::MemoryBuffer::getMemBuffer(main);
225   FileID mainFileID = SourceMgr.createFileID(std::move(MainBuf));
226   SourceMgr.setMainFileID(mainFileID);
227 
228   const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h",
229                                                  HeaderBuf->getBufferSize(), 0);
230   SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf));
231 
232   TrivialModuleLoader ModLoader;
233   MemoryBufferCache PCMCache;
234   HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
235                           Diags, LangOpts, &*Target);
236   Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
237                   SourceMgr, PCMCache, HeaderInfo, ModLoader,
238                   /*IILookup =*/nullptr,
239                   /*OwnsHeaderSearch =*/false);
240   PP.Initialize(*Target);
241   PP.EnterMainSourceFile();
242 
243   std::vector<Token> toks;
244   while (1) {
245     Token tok;
246     PP.Lex(tok);
247     if (tok.is(tok::eof))
248       break;
249     toks.push_back(tok);
250   }
251 
252   // Make sure we got the tokens that we expected.
253   ASSERT_EQ(4U, toks.size());
254   ASSERT_EQ(tok::numeric_constant, toks[0].getKind());
255   ASSERT_EQ(tok::numeric_constant, toks[1].getKind());
256   ASSERT_EQ(tok::numeric_constant, toks[2].getKind());
257   ASSERT_EQ(tok::numeric_constant, toks[3].getKind());
258 
259   SourceLocation defLoc = SourceMgr.translateLineCol(mainFileID, 2, 13);
260   SourceLocation loc1 = SourceMgr.translateLineCol(mainFileID, 3, 8);
261   SourceLocation loc2 = SourceMgr.translateLineCol(mainFileID, 4, 4);
262   SourceLocation loc3 = SourceMgr.translateLineCol(mainFileID, 5, 7);
263   SourceLocation defLoc2 = SourceMgr.translateLineCol(mainFileID, 6, 22);
264   defLoc = SourceMgr.getMacroArgExpandedLocation(defLoc);
265   loc1 = SourceMgr.getMacroArgExpandedLocation(loc1);
266   loc2 = SourceMgr.getMacroArgExpandedLocation(loc2);
267   loc3 = SourceMgr.getMacroArgExpandedLocation(loc3);
268   defLoc2 = SourceMgr.getMacroArgExpandedLocation(defLoc2);
269 
270   EXPECT_TRUE(defLoc.isFileID());
271   EXPECT_TRUE(loc1.isFileID());
272   EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc2));
273   EXPECT_TRUE(SourceMgr.isMacroArgExpansion(loc3));
274   EXPECT_EQ(loc2, toks[1].getLocation());
275   EXPECT_EQ(loc3, toks[2].getLocation());
276   EXPECT_TRUE(defLoc2.isFileID());
277 }
278 
279 namespace {
280 
281 struct MacroAction {
282   enum Kind { kExpansion, kDefinition, kUnDefinition};
283 
284   SourceLocation Loc;
285   std::string Name;
286   unsigned MAKind : 3;
287 
288   MacroAction(SourceLocation Loc, StringRef Name, unsigned K)
289     : Loc(Loc), Name(Name), MAKind(K) { }
290 
291   bool isExpansion() const { return MAKind == kExpansion; }
292   bool isDefinition() const { return MAKind & kDefinition; }
293   bool isUnDefinition() const { return MAKind & kUnDefinition; }
294 };
295 
296 class MacroTracker : public PPCallbacks {
297   std::vector<MacroAction> &Macros;
298 
299 public:
300   explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) { }
301 
302   void MacroDefined(const Token &MacroNameTok,
303                     const MacroDirective *MD) override {
304     Macros.push_back(MacroAction(MD->getLocation(),
305                                  MacroNameTok.getIdentifierInfo()->getName(),
306                                  MacroAction::kDefinition));
307   }
308   void MacroUndefined(const Token &MacroNameTok,
309                       const MacroDefinition &MD,
310                       const MacroDirective  *UD) override {
311     Macros.push_back(
312         MacroAction(UD ? UD->getLocation() : SourceLocation(),
313                     MacroNameTok.getIdentifierInfo()->getName(),
314                     UD ? MacroAction::kDefinition | MacroAction::kUnDefinition
315                        : MacroAction::kUnDefinition));
316   }
317   void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
318                     SourceRange Range, const MacroArgs *Args) override {
319     Macros.push_back(MacroAction(MacroNameTok.getLocation(),
320                                  MacroNameTok.getIdentifierInfo()->getName(),
321                                  MacroAction::kExpansion));
322   }
323 };
324 
325 }
326 
327 TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
328   const char *header =
329     "#define MACRO_IN_INCLUDE 0\n"
330     "#define MACRO_DEFINED\n"
331     "#undef MACRO_DEFINED\n"
332     "#undef MACRO_UNDEFINED\n";
333 
334   const char *main =
335     "#define M(x) x\n"
336     "#define INC \"/test-header.h\"\n"
337     "#include M(INC)\n"
338     "#define INC2 </test-header.h>\n"
339     "#include M(INC2)\n";
340 
341   std::unique_ptr<llvm::MemoryBuffer> HeaderBuf =
342       llvm::MemoryBuffer::getMemBuffer(header);
343   std::unique_ptr<llvm::MemoryBuffer> MainBuf =
344       llvm::MemoryBuffer::getMemBuffer(main);
345   SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(MainBuf)));
346 
347   const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h",
348                                                  HeaderBuf->getBufferSize(), 0);
349   SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf));
350 
351   TrivialModuleLoader ModLoader;
352   MemoryBufferCache PCMCache;
353   HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
354                           Diags, LangOpts, &*Target);
355   Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
356                   SourceMgr, PCMCache, HeaderInfo, ModLoader,
357                   /*IILookup =*/nullptr,
358                   /*OwnsHeaderSearch =*/false);
359   PP.Initialize(*Target);
360 
361   std::vector<MacroAction> Macros;
362   PP.addPPCallbacks(llvm::make_unique<MacroTracker>(Macros));
363 
364   PP.EnterMainSourceFile();
365 
366   std::vector<Token> toks;
367   while (1) {
368     Token tok;
369     PP.Lex(tok);
370     if (tok.is(tok::eof))
371       break;
372     toks.push_back(tok);
373   }
374 
375   // Make sure we got the tokens that we expected.
376   ASSERT_EQ(0U, toks.size());
377 
378   ASSERT_EQ(15U, Macros.size());
379   // #define M(x) x
380   ASSERT_TRUE(Macros[0].isDefinition());
381   ASSERT_EQ("M", Macros[0].Name);
382   // #define INC "/test-header.h"
383   ASSERT_TRUE(Macros[1].isDefinition());
384   ASSERT_EQ("INC", Macros[1].Name);
385   // M expansion in #include M(INC)
386   ASSERT_FALSE(Macros[2].isDefinition());
387   ASSERT_EQ("M", Macros[2].Name);
388   // INC expansion in #include M(INC)
389   ASSERT_TRUE(Macros[3].isExpansion());
390   ASSERT_EQ("INC", Macros[3].Name);
391   // #define MACRO_IN_INCLUDE 0
392   ASSERT_TRUE(Macros[4].isDefinition());
393   ASSERT_EQ("MACRO_IN_INCLUDE", Macros[4].Name);
394   // #define MACRO_DEFINED
395   ASSERT_TRUE(Macros[5].isDefinition());
396   ASSERT_FALSE(Macros[5].isUnDefinition());
397   ASSERT_EQ("MACRO_DEFINED", Macros[5].Name);
398   // #undef MACRO_DEFINED
399   ASSERT_TRUE(Macros[6].isDefinition());
400   ASSERT_TRUE(Macros[6].isUnDefinition());
401   ASSERT_EQ("MACRO_DEFINED", Macros[6].Name);
402   // #undef MACRO_UNDEFINED
403   ASSERT_FALSE(Macros[7].isDefinition());
404   ASSERT_TRUE(Macros[7].isUnDefinition());
405   ASSERT_EQ("MACRO_UNDEFINED", Macros[7].Name);
406   // #define INC2 </test-header.h>
407   ASSERT_TRUE(Macros[8].isDefinition());
408   ASSERT_EQ("INC2", Macros[8].Name);
409   // M expansion in #include M(INC2)
410   ASSERT_FALSE(Macros[9].isDefinition());
411   ASSERT_EQ("M", Macros[9].Name);
412   // INC2 expansion in #include M(INC2)
413   ASSERT_TRUE(Macros[10].isExpansion());
414   ASSERT_EQ("INC2", Macros[10].Name);
415   // #define MACRO_IN_INCLUDE 0
416   ASSERT_TRUE(Macros[11].isDefinition());
417   ASSERT_EQ("MACRO_IN_INCLUDE", Macros[11].Name);
418 
419   // The INC expansion in #include M(INC) comes before the first
420   // MACRO_IN_INCLUDE definition of the included file.
421   EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[3].Loc, Macros[4].Loc));
422 
423   // The INC2 expansion in #include M(INC2) comes before the second
424   // MACRO_IN_INCLUDE definition of the included file.
425   EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[10].Loc, Macros[11].Loc));
426 }
427 
428 #endif
429 
430 } // anonymous namespace
431