xref: /llvm-project/clang/unittests/Basic/SourceManagerTest.cpp (revision b7755111a26f0ba590ef2a73f339f34570c3827a)
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   enum Kind { kExpansion, kDefinition, kUnDefinition};
253 
254   SourceLocation Loc;
255   std::string Name;
256   unsigned MAKind : 3;
257 
258   MacroAction(SourceLocation Loc, StringRef Name, unsigned K)
259     : Loc(Loc), Name(Name), MAKind(K) { }
260 
261   bool isExpansion() const { return MAKind == kExpansion; }
262   bool isDefinition() const { return MAKind & kDefinition; }
263   bool isUnDefinition() const { return MAKind & kUnDefinition; }
264 };
265 
266 class MacroTracker : public PPCallbacks {
267   std::vector<MacroAction> &Macros;
268 
269 public:
270   explicit MacroTracker(std::vector<MacroAction> &Macros) : Macros(Macros) { }
271 
272   void MacroDefined(const Token &MacroNameTok,
273                     const MacroDirective *MD) override {
274     Macros.push_back(MacroAction(MD->getLocation(),
275                                  MacroNameTok.getIdentifierInfo()->getName(),
276                                  MacroAction::kDefinition));
277   }
278   void MacroUndefined(const Token &MacroNameTok,
279                       const MacroDefinition &MD,
280                       const MacroDirective  *UD) override {
281     Macros.push_back(
282         MacroAction(UD ? UD->getLocation() : SourceLocation(),
283                     MacroNameTok.getIdentifierInfo()->getName(),
284                     UD ? MacroAction::kDefinition | MacroAction::kUnDefinition
285                        : MacroAction::kUnDefinition));
286   }
287   void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
288                     SourceRange Range, const MacroArgs *Args) override {
289     Macros.push_back(MacroAction(MacroNameTok.getLocation(),
290                                  MacroNameTok.getIdentifierInfo()->getName(),
291                                  MacroAction::kExpansion));
292   }
293 };
294 
295 }
296 
297 TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) {
298   const char *header =
299     "#define MACRO_IN_INCLUDE 0\n"
300     "#define MACRO_DEFINED\n"
301     "#undef MACRO_DEFINED\n"
302     "#undef MACRO_UNDEFINED\n";
303 
304   const char *main =
305     "#define M(x) x\n"
306     "#define INC \"/test-header.h\"\n"
307     "#include M(INC)\n"
308     "#define INC2 </test-header.h>\n"
309     "#include M(INC2)\n";
310 
311   std::unique_ptr<llvm::MemoryBuffer> HeaderBuf =
312       llvm::MemoryBuffer::getMemBuffer(header);
313   std::unique_ptr<llvm::MemoryBuffer> MainBuf =
314       llvm::MemoryBuffer::getMemBuffer(main);
315   SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(MainBuf)));
316 
317   const FileEntry *headerFile = FileMgr.getVirtualFile("/test-header.h",
318                                                  HeaderBuf->getBufferSize(), 0);
319   SourceMgr.overrideFileContents(headerFile, std::move(HeaderBuf));
320 
321   VoidModuleLoader ModLoader;
322   MemoryBufferCache PCMCache;
323   HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
324                           Diags, LangOpts, &*Target);
325   Preprocessor PP(std::make_shared<PreprocessorOptions>(), Diags, LangOpts,
326                   SourceMgr, PCMCache, HeaderInfo, ModLoader,
327                   /*IILookup =*/nullptr,
328                   /*OwnsHeaderSearch =*/false);
329   PP.Initialize(*Target);
330 
331   std::vector<MacroAction> Macros;
332   PP.addPPCallbacks(llvm::make_unique<MacroTracker>(Macros));
333 
334   PP.EnterMainSourceFile();
335 
336   std::vector<Token> toks;
337   while (1) {
338     Token tok;
339     PP.Lex(tok);
340     if (tok.is(tok::eof))
341       break;
342     toks.push_back(tok);
343   }
344 
345   // Make sure we got the tokens that we expected.
346   ASSERT_EQ(0U, toks.size());
347 
348   ASSERT_EQ(15U, Macros.size());
349   // #define M(x) x
350   ASSERT_TRUE(Macros[0].isDefinition());
351   ASSERT_EQ("M", Macros[0].Name);
352   // #define INC "/test-header.h"
353   ASSERT_TRUE(Macros[1].isDefinition());
354   ASSERT_EQ("INC", Macros[1].Name);
355   // M expansion in #include M(INC)
356   ASSERT_FALSE(Macros[2].isDefinition());
357   ASSERT_EQ("M", Macros[2].Name);
358   // INC expansion in #include M(INC)
359   ASSERT_TRUE(Macros[3].isExpansion());
360   ASSERT_EQ("INC", Macros[3].Name);
361   // #define MACRO_IN_INCLUDE 0
362   ASSERT_TRUE(Macros[4].isDefinition());
363   ASSERT_EQ("MACRO_IN_INCLUDE", Macros[4].Name);
364   // #define MACRO_DEFINED
365   ASSERT_TRUE(Macros[5].isDefinition());
366   ASSERT_FALSE(Macros[5].isUnDefinition());
367   ASSERT_EQ("MACRO_DEFINED", Macros[5].Name);
368   // #undef MACRO_DEFINED
369   ASSERT_TRUE(Macros[6].isDefinition());
370   ASSERT_TRUE(Macros[6].isUnDefinition());
371   ASSERT_EQ("MACRO_DEFINED", Macros[6].Name);
372   // #undef MACRO_UNDEFINED
373   ASSERT_FALSE(Macros[7].isDefinition());
374   ASSERT_TRUE(Macros[7].isUnDefinition());
375   ASSERT_EQ("MACRO_UNDEFINED", Macros[7].Name);
376   // #define INC2 </test-header.h>
377   ASSERT_TRUE(Macros[8].isDefinition());
378   ASSERT_EQ("INC2", Macros[8].Name);
379   // M expansion in #include M(INC2)
380   ASSERT_FALSE(Macros[9].isDefinition());
381   ASSERT_EQ("M", Macros[9].Name);
382   // INC2 expansion in #include M(INC2)
383   ASSERT_TRUE(Macros[10].isExpansion());
384   ASSERT_EQ("INC2", Macros[10].Name);
385   // #define MACRO_IN_INCLUDE 0
386   ASSERT_TRUE(Macros[11].isDefinition());
387   ASSERT_EQ("MACRO_IN_INCLUDE", Macros[11].Name);
388 
389   // The INC expansion in #include M(INC) comes before the first
390   // MACRO_IN_INCLUDE definition of the included file.
391   EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[3].Loc, Macros[4].Loc));
392 
393   // The INC2 expansion in #include M(INC2) comes before the second
394   // MACRO_IN_INCLUDE definition of the included file.
395   EXPECT_TRUE(SourceMgr.isBeforeInTranslationUnit(Macros[10].Loc, Macros[11].Loc));
396 }
397 
398 #endif
399 
400 } // anonymous namespace
401