1 //===- unittests/Basic/SourceManagerTest.cpp ------ SourceManager tests ---===//
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
7 //===----------------------------------------------------------------------===//
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 "llvm/Support/MemoryBuffer.h"
24 #include "llvm/Support/Process.h"
25 #include "gtest/gtest.h"
28 using namespace clang
;
31 class SourceManagerTestHelper
{
33 static FileID
makeFileID(int ID
) { return FileID::get(ID
); }
40 class SourceManagerTest
: public ::testing::Test
{
43 : FileMgr(FileMgrOpts
),
44 DiagID(new DiagnosticIDs()),
45 Diags(DiagID
, new DiagnosticOptions
, new IgnoringDiagConsumer()),
46 SourceMgr(Diags
, FileMgr
),
47 TargetOpts(new TargetOptions
) {
48 TargetOpts
->Triple
= "x86_64-apple-darwin11.1.0";
49 Target
= TargetInfo::CreateTargetInfo(Diags
, TargetOpts
);
52 FileSystemOptions FileMgrOpts
;
54 IntrusiveRefCntPtr
<DiagnosticIDs
> DiagID
;
55 DiagnosticsEngine Diags
;
56 SourceManager SourceMgr
;
58 std::shared_ptr
<TargetOptions
> TargetOpts
;
59 IntrusiveRefCntPtr
<TargetInfo
> Target
;
62 TEST_F(SourceManagerTest
, isInMemoryBuffersNoSourceLocationInfo
) {
63 // Check for invalid source location for each method
64 SourceLocation LocEmpty
;
65 bool isWrittenInBuiltInFileFalse
= SourceMgr
.isWrittenInBuiltinFile(LocEmpty
);
66 bool isWrittenInCommandLineFileFalse
=
67 SourceMgr
.isWrittenInCommandLineFile(LocEmpty
);
68 bool isWrittenInScratchSpaceFalse
=
69 SourceMgr
.isWrittenInScratchSpace(LocEmpty
);
71 EXPECT_FALSE(isWrittenInBuiltInFileFalse
);
72 EXPECT_FALSE(isWrittenInCommandLineFileFalse
);
73 EXPECT_FALSE(isWrittenInScratchSpaceFalse
);
75 // Check for valid source location per filename for each method
76 const char *Source
= "int x";
78 std::unique_ptr
<llvm::MemoryBuffer
> BuiltInBuf
=
79 llvm::MemoryBuffer::getMemBuffer(Source
);
80 FileEntryRef BuiltInFile
=
81 FileMgr
.getVirtualFileRef("<built-in>", BuiltInBuf
->getBufferSize(), 0);
82 SourceMgr
.overrideFileContents(BuiltInFile
, std::move(BuiltInBuf
));
83 FileID BuiltInFileID
=
84 SourceMgr
.getOrCreateFileID(BuiltInFile
, SrcMgr::C_User
);
85 SourceMgr
.setMainFileID(BuiltInFileID
);
86 SourceLocation LocBuiltIn
=
87 SourceMgr
.getLocForStartOfFile(SourceMgr
.getMainFileID());
88 bool isWrittenInBuiltInFileTrue
=
89 SourceMgr
.isWrittenInBuiltinFile(LocBuiltIn
);
91 std::unique_ptr
<llvm::MemoryBuffer
> CommandLineBuf
=
92 llvm::MemoryBuffer::getMemBuffer(Source
);
93 FileEntryRef CommandLineFile
= FileMgr
.getVirtualFileRef(
94 "<command line>", CommandLineBuf
->getBufferSize(), 0);
95 SourceMgr
.overrideFileContents(CommandLineFile
, std::move(CommandLineBuf
));
96 FileID CommandLineFileID
=
97 SourceMgr
.getOrCreateFileID(CommandLineFile
, SrcMgr::C_User
);
98 SourceMgr
.setMainFileID(CommandLineFileID
);
99 SourceLocation LocCommandLine
=
100 SourceMgr
.getLocForStartOfFile(SourceMgr
.getMainFileID());
101 bool isWrittenInCommandLineFileTrue
=
102 SourceMgr
.isWrittenInCommandLineFile(LocCommandLine
);
104 std::unique_ptr
<llvm::MemoryBuffer
> ScratchSpaceBuf
=
105 llvm::MemoryBuffer::getMemBuffer(Source
);
106 FileEntryRef ScratchSpaceFile
= FileMgr
.getVirtualFileRef(
107 "<scratch space>", ScratchSpaceBuf
->getBufferSize(), 0);
108 SourceMgr
.overrideFileContents(ScratchSpaceFile
, std::move(ScratchSpaceBuf
));
109 FileID ScratchSpaceFileID
=
110 SourceMgr
.getOrCreateFileID(ScratchSpaceFile
, SrcMgr::C_User
);
111 SourceMgr
.setMainFileID(ScratchSpaceFileID
);
112 SourceLocation LocScratchSpace
=
113 SourceMgr
.getLocForStartOfFile(SourceMgr
.getMainFileID());
114 bool isWrittenInScratchSpaceTrue
=
115 SourceMgr
.isWrittenInScratchSpace(LocScratchSpace
);
117 EXPECT_TRUE(isWrittenInBuiltInFileTrue
);
118 EXPECT_TRUE(isWrittenInCommandLineFileTrue
);
119 EXPECT_TRUE(isWrittenInScratchSpaceTrue
);
122 TEST_F(SourceManagerTest
, isInSystemHeader
) {
123 // Check for invalid source location
124 SourceLocation LocEmpty
;
125 bool isInSystemHeaderFalse
= SourceMgr
.isInSystemHeader(LocEmpty
);
126 ASSERT_FALSE(isInSystemHeaderFalse
);
129 TEST_F(SourceManagerTest
, isBeforeInTranslationUnit
) {
133 std::unique_ptr
<llvm::MemoryBuffer
> Buf
=
134 llvm::MemoryBuffer::getMemBuffer(source
);
135 FileID mainFileID
= SourceMgr
.createFileID(std::move(Buf
));
136 SourceMgr
.setMainFileID(mainFileID
);
138 TrivialModuleLoader ModLoader
;
139 HeaderSearch
HeaderInfo(std::make_shared
<HeaderSearchOptions
>(), SourceMgr
,
140 Diags
, LangOpts
, &*Target
);
141 Preprocessor
PP(std::make_shared
<PreprocessorOptions
>(), Diags
, LangOpts
,
142 SourceMgr
, HeaderInfo
, ModLoader
,
143 /*IILookup =*/nullptr,
144 /*OwnsHeaderSearch =*/false);
145 PP
.Initialize(*Target
);
146 PP
.EnterMainSourceFile();
148 std::vector
<Token
> toks
;
149 PP
.LexTokensUntilEOF(&toks
);
151 // Make sure we got the tokens that we expected.
152 ASSERT_EQ(3U, toks
.size());
153 ASSERT_EQ(tok::l_square
, toks
[0].getKind());
154 ASSERT_EQ(tok::identifier
, toks
[1].getKind());
155 ASSERT_EQ(tok::r_square
, toks
[2].getKind());
157 SourceLocation lsqrLoc
= toks
[0].getLocation();
158 SourceLocation idLoc
= toks
[1].getLocation();
159 SourceLocation rsqrLoc
= toks
[2].getLocation();
161 SourceLocation macroExpStartLoc
= SourceMgr
.translateLineCol(mainFileID
, 2, 1);
162 SourceLocation macroExpEndLoc
= SourceMgr
.translateLineCol(mainFileID
, 2, 6);
163 ASSERT_TRUE(macroExpStartLoc
.isFileID());
164 ASSERT_TRUE(macroExpEndLoc
.isFileID());
167 ASSERT_EQ("M", PP
.getSpelling(macroExpStartLoc
, str
));
168 ASSERT_EQ(")", PP
.getSpelling(macroExpEndLoc
, str
));
170 EXPECT_TRUE(SourceMgr
.isBeforeInTranslationUnit(lsqrLoc
, idLoc
));
171 EXPECT_TRUE(SourceMgr
.isBeforeInTranslationUnit(idLoc
, rsqrLoc
));
172 EXPECT_TRUE(SourceMgr
.isBeforeInTranslationUnit(macroExpStartLoc
, idLoc
));
173 EXPECT_TRUE(SourceMgr
.isBeforeInTranslationUnit(idLoc
, macroExpEndLoc
));
176 TEST_F(SourceManagerTest
, isBeforeInTranslationUnitWithTokenSplit
) {
177 const char *main
= R
"cpp(
185 SourceMgr
.setMainFileID(
186 SourceMgr
.createFileID(llvm::MemoryBuffer::getMemBuffer(main
)));
188 TrivialModuleLoader ModLoader
;
189 HeaderSearch
HeaderInfo(std::make_shared
<HeaderSearchOptions
>(), SourceMgr
,
190 Diags
, LangOpts
, &*Target
);
191 Preprocessor
PP(std::make_shared
<PreprocessorOptions
>(), Diags
, LangOpts
,
192 SourceMgr
, HeaderInfo
, ModLoader
,
193 /*IILookup =*/nullptr,
194 /*OwnsHeaderSearch =*/false);
195 PP
.Initialize(*Target
);
196 PP
.EnterMainSourceFile();
197 llvm::SmallString
<8> Scratch
;
199 std::vector
<Token
> toks
;
200 PP
.LexTokensUntilEOF(&toks
);
202 // Make sure we got the tokens that we expected.
203 ASSERT_EQ(4U, toks
.size()) << "a >> b c";
204 // Sanity check their order.
205 for (unsigned I
= 0; I
< toks
.size() - 1; ++I
) {
206 EXPECT_TRUE(SourceMgr
.isBeforeInTranslationUnit(toks
[I
].getLocation(),
207 toks
[I
+ 1].getLocation()));
208 EXPECT_FALSE(SourceMgr
.isBeforeInTranslationUnit(toks
[I
+ 1].getLocation(),
209 toks
[I
].getLocation()));
212 // Split the >> into two > tokens, as happens when parsing nested templates.
213 unsigned RightShiftIndex
= 1;
214 SourceLocation RightShift
= toks
[RightShiftIndex
].getLocation();
215 EXPECT_EQ(">>", Lexer::getSpelling(SourceMgr
.getSpellingLoc(RightShift
),
216 Scratch
, SourceMgr
, LangOpts
));
217 SourceLocation Greater1
= PP
.SplitToken(RightShift
, /*Length=*/1);
218 SourceLocation Greater2
= RightShift
.getLocWithOffset(1);
219 EXPECT_TRUE(Greater1
.isMacroID());
220 EXPECT_EQ(">", Lexer::getSpelling(SourceMgr
.getSpellingLoc(Greater1
), Scratch
,
221 SourceMgr
, LangOpts
));
222 EXPECT_EQ(">", Lexer::getSpelling(SourceMgr
.getSpellingLoc(Greater2
), Scratch
,
223 SourceMgr
, LangOpts
));
224 EXPECT_EQ(SourceMgr
.getImmediateExpansionRange(Greater1
).getBegin(),
227 for (unsigned I
= 0; I
< toks
.size(); ++I
) {
228 SCOPED_TRACE("Token " + std::to_string(I
));
229 // Right-shift is the parent of Greater1, so it compares less.
231 SourceMgr
.isBeforeInTranslationUnit(toks
[I
].getLocation(), Greater1
),
232 I
<= RightShiftIndex
);
234 SourceMgr
.isBeforeInTranslationUnit(toks
[I
].getLocation(), Greater2
),
235 I
<= RightShiftIndex
);
237 SourceMgr
.isBeforeInTranslationUnit(Greater1
, toks
[I
].getLocation()),
238 RightShiftIndex
< I
);
240 SourceMgr
.isBeforeInTranslationUnit(Greater2
, toks
[I
].getLocation()),
241 RightShiftIndex
< I
);
243 EXPECT_TRUE(SourceMgr
.isBeforeInTranslationUnit(Greater1
, Greater2
));
244 EXPECT_FALSE(SourceMgr
.isBeforeInTranslationUnit(Greater2
, Greater1
));
247 TEST_F(SourceManagerTest
, getColumnNumber
) {
252 std::unique_ptr
<llvm::MemoryBuffer
> Buf
=
253 llvm::MemoryBuffer::getMemBuffer(Source
);
254 FileID MainFileID
= SourceMgr
.createFileID(std::move(Buf
));
255 SourceMgr
.setMainFileID(MainFileID
);
260 EXPECT_EQ(1U, SourceMgr
.getColumnNumber(MainFileID
, 0, &Invalid
));
261 EXPECT_TRUE(!Invalid
);
264 EXPECT_EQ(5U, SourceMgr
.getColumnNumber(MainFileID
, 4, &Invalid
));
265 EXPECT_TRUE(!Invalid
);
268 EXPECT_EQ(1U, SourceMgr
.getColumnNumber(MainFileID
, 7, &Invalid
));
269 EXPECT_TRUE(!Invalid
);
272 EXPECT_EQ(5U, SourceMgr
.getColumnNumber(MainFileID
, 11, &Invalid
));
273 EXPECT_TRUE(!Invalid
);
276 EXPECT_EQ(7U, SourceMgr
.getColumnNumber(MainFileID
, strlen(Source
),
278 EXPECT_TRUE(!Invalid
);
281 SourceMgr
.getColumnNumber(MainFileID
, strlen(Source
)+1, &Invalid
);
282 EXPECT_TRUE(Invalid
);
284 // Test invalid files
286 SourceMgr
.getColumnNumber(FileID(), 0, &Invalid
);
287 EXPECT_TRUE(Invalid
);
290 SourceMgr
.getColumnNumber(FileID(), 1, &Invalid
);
291 EXPECT_TRUE(Invalid
);
293 // Test with no invalid flag.
294 EXPECT_EQ(1U, SourceMgr
.getColumnNumber(MainFileID
, 0, nullptr));
297 TEST_F(SourceManagerTest
, locationPrintTest
) {
298 const char *header
= "#define IDENTITY(x) x\n";
300 const char *Source
= "int x;\n"
301 "include \"test-header.h\"\n"
305 std::unique_ptr
<llvm::MemoryBuffer
> HeaderBuf
=
306 llvm::MemoryBuffer::getMemBuffer(header
);
307 std::unique_ptr
<llvm::MemoryBuffer
> Buf
=
308 llvm::MemoryBuffer::getMemBuffer(Source
);
310 FileEntryRef SourceFile
=
311 FileMgr
.getVirtualFileRef("/mainFile.cpp", Buf
->getBufferSize(), 0);
312 SourceMgr
.overrideFileContents(SourceFile
, std::move(Buf
));
314 FileEntryRef HeaderFile
= FileMgr
.getVirtualFileRef(
315 "/test-header.h", HeaderBuf
->getBufferSize(), 0);
316 SourceMgr
.overrideFileContents(HeaderFile
, std::move(HeaderBuf
));
318 FileID MainFileID
= SourceMgr
.getOrCreateFileID(SourceFile
, SrcMgr::C_User
);
319 FileID HeaderFileID
= SourceMgr
.getOrCreateFileID(HeaderFile
, SrcMgr::C_User
);
320 SourceMgr
.setMainFileID(MainFileID
);
322 auto BeginLoc
= SourceMgr
.getLocForStartOfFile(MainFileID
);
323 auto EndLoc
= SourceMgr
.getLocForEndOfFile(MainFileID
);
325 auto BeginEOLLoc
= SourceMgr
.translateLineCol(MainFileID
, 1, 7);
327 auto HeaderLoc
= SourceMgr
.getLocForStartOfFile(HeaderFileID
);
329 EXPECT_EQ(BeginLoc
.printToString(SourceMgr
), "/mainFile.cpp:1:1");
330 EXPECT_EQ(EndLoc
.printToString(SourceMgr
), "/mainFile.cpp:4:7");
332 EXPECT_EQ(BeginEOLLoc
.printToString(SourceMgr
), "/mainFile.cpp:1:7");
333 EXPECT_EQ(HeaderLoc
.printToString(SourceMgr
), "/test-header.h:1:1");
335 EXPECT_EQ(SourceRange(BeginLoc
, BeginLoc
).printToString(SourceMgr
),
336 "</mainFile.cpp:1:1>");
337 EXPECT_EQ(SourceRange(BeginLoc
, BeginEOLLoc
).printToString(SourceMgr
),
338 "</mainFile.cpp:1:1, col:7>");
339 EXPECT_EQ(SourceRange(BeginLoc
, EndLoc
).printToString(SourceMgr
),
340 "</mainFile.cpp:1:1, line:4:7>");
341 EXPECT_EQ(SourceRange(BeginLoc
, HeaderLoc
).printToString(SourceMgr
),
342 "</mainFile.cpp:1:1, /test-header.h:1:1>");
345 TEST_F(SourceManagerTest
, getInvalidBOM
) {
346 ASSERT_EQ(SrcMgr::ContentCache::getInvalidBOM(""), nullptr);
347 ASSERT_EQ(SrcMgr::ContentCache::getInvalidBOM("\x00\x00\x00"), nullptr);
348 ASSERT_EQ(SrcMgr::ContentCache::getInvalidBOM("\xFF\xFF\xFF"), nullptr);
349 ASSERT_EQ(SrcMgr::ContentCache::getInvalidBOM("#include <iostream>"),
352 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM(
353 "\xFE\xFF#include <iostream>")),
355 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM(
356 "\xFF\xFE#include <iostream>")),
358 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM(
359 "\x2B\x2F\x76#include <iostream>")),
361 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM(
362 "\xF7\x64\x4C#include <iostream>")),
364 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM(
365 "\xDD\x73\x66\x73#include <iostream>")),
367 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM(
368 "\x0E\xFE\xFF#include <iostream>")),
370 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM(
371 "\xFB\xEE\x28#include <iostream>")),
373 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM(
374 "\x84\x31\x95\x33#include <iostream>")),
376 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM(
377 llvm::StringLiteral::withInnerNUL(
378 "\x00\x00\xFE\xFF#include <iostream>"))),
380 ASSERT_EQ(StringRef(SrcMgr::ContentCache::getInvalidBOM(
381 llvm::StringLiteral::withInnerNUL(
382 "\xFF\xFE\x00\x00#include <iostream>"))),
386 // Regression test - there was an out of bound access for buffers not terminated by zero.
387 TEST_F(SourceManagerTest
, getLineNumber
) {
388 const unsigned pageSize
= llvm::sys::Process::getPageSizeEstimate();
389 std::unique_ptr
<char[]> source(new char[pageSize
]);
390 for(unsigned i
= 0; i
< pageSize
; ++i
) {
394 std::unique_ptr
<llvm::MemoryBuffer
> Buf
=
395 llvm::MemoryBuffer::getMemBuffer(
396 llvm::MemoryBufferRef(
397 llvm::StringRef(source
.get(), 3), "whatever"
402 FileID mainFileID
= SourceMgr
.createFileID(std::move(Buf
));
403 SourceMgr
.setMainFileID(mainFileID
);
405 ASSERT_NO_FATAL_FAILURE(SourceMgr
.getLineNumber(mainFileID
, 1, nullptr));
408 struct FakeExternalSLocEntrySource
: ExternalSLocEntrySource
{
409 bool ReadSLocEntry(int ID
) override
{ return {}; }
410 int getSLocEntryID(SourceLocation::UIntTy SLocOffset
) override
{ return 0; }
411 std::pair
<SourceLocation
, StringRef
> getModuleImportLoc(int ID
) override
{
416 TEST_F(SourceManagerTest
, loadedSLocEntryIsInTheSameTranslationUnit
) {
417 auto InSameTU
= [=](int LID
, int RID
) {
418 return SourceMgr
.isInTheSameTranslationUnitImpl(
419 std::make_pair(SourceManagerTestHelper::makeFileID(LID
), 0),
420 std::make_pair(SourceManagerTestHelper::makeFileID(RID
), 0));
423 FakeExternalSLocEntrySource ExternalSource
;
424 SourceMgr
.setExternalSLocEntrySource(&ExternalSource
);
426 unsigned ANumFileIDs
= 10;
427 auto [AFirstID
, X
] = SourceMgr
.AllocateLoadedSLocEntries(ANumFileIDs
, 10);
428 int ALastID
= AFirstID
+ ANumFileIDs
- 1;
429 // FileID(-11)..FileID(-2)
430 ASSERT_EQ(AFirstID
, -11);
431 ASSERT_EQ(ALastID
, -2);
433 unsigned BNumFileIDs
= 20;
434 auto [BFirstID
, Y
] = SourceMgr
.AllocateLoadedSLocEntries(BNumFileIDs
, 20);
435 int BLastID
= BFirstID
+ BNumFileIDs
- 1;
436 // FileID(-31)..FileID(-12)
437 ASSERT_EQ(BFirstID
, -31);
438 ASSERT_EQ(BLastID
, -12);
441 EXPECT_FALSE(InSameTU(-2, 1));
443 // Loaded in the same allocation A.
444 EXPECT_TRUE(InSameTU(-11, -2));
445 EXPECT_TRUE(InSameTU(-11, -6));
447 // Loaded in the same allocation B.
448 EXPECT_TRUE(InSameTU(-31, -12));
449 EXPECT_TRUE(InSameTU(-31, -16));
451 // Loaded from different allocations A and B.
452 EXPECT_FALSE(InSameTU(-12, -11));
455 #if defined(LLVM_ON_UNIX)
457 // A single SourceManager instance is sometimes reused across multiple
458 // compilations. This test makes sure we're resetting caches built for tracking
459 // include locations that are based on FileIDs, to make sure we don't report
460 // wrong include locations when FileIDs coincide between two different runs.
461 TEST_F(SourceManagerTest
, ResetsIncludeLocMap
) {
462 auto ParseFile
= [&] {
463 TrivialModuleLoader ModLoader
;
464 HeaderSearch
HeaderInfo(std::make_shared
<HeaderSearchOptions
>(), SourceMgr
,
465 Diags
, LangOpts
, &*Target
);
466 Preprocessor
PP(std::make_shared
<PreprocessorOptions
>(), Diags
, LangOpts
,
467 SourceMgr
, HeaderInfo
, ModLoader
,
468 /*IILookup =*/nullptr,
469 /*OwnsHeaderSearch =*/false);
470 PP
.Initialize(*Target
);
471 PP
.EnterMainSourceFile();
472 PP
.LexTokensUntilEOF();
473 EXPECT_FALSE(Diags
.hasErrorOccurred());
476 auto Buf
= llvm::MemoryBuffer::getMemBuffer("");
477 FileEntryRef HeaderFile
=
478 FileMgr
.getVirtualFileRef("/foo.h", Buf
->getBufferSize(), 0);
479 SourceMgr
.overrideFileContents(HeaderFile
, std::move(Buf
));
481 Buf
= llvm::MemoryBuffer::getMemBuffer(R
"cpp(#include "/foo
.h
")cpp");
482 FileEntryRef BarFile
=
483 FileMgr
.getVirtualFileRef("/bar.h", Buf
->getBufferSize(), 0);
484 SourceMgr
.overrideFileContents(BarFile
, std::move(Buf
));
485 SourceMgr
.createFileID(BarFile
, {}, clang::SrcMgr::C_User
);
487 Buf
= llvm::MemoryBuffer::getMemBuffer(R
"cpp(#include "/foo
.h
")cpp");
488 FileID MFID
= SourceMgr
.createFileID(std::move(Buf
));
489 SourceMgr
.setMainFileID(MFID
);
492 auto FooFID
= SourceMgr
.getOrCreateFileID(HeaderFile
, clang::SrcMgr::C_User
);
493 auto IncFID
= SourceMgr
.getDecomposedIncludedLoc(FooFID
).first
;
494 EXPECT_EQ(IncFID
, MFID
);
496 // Clean up source-manager state before we start next parse.
497 SourceMgr
.clearIDTables();
499 // Set up a new main file.
500 Buf
= llvm::MemoryBuffer::getMemBuffer(R
"cpp(
502 #include "/bar
.h
")cpp");
503 MFID
= SourceMgr
.createFileID(std::move(Buf
));
504 SourceMgr
.setMainFileID(MFID
);
507 // Make sure foo.h got the same file-id in both runs.
509 SourceMgr
.getOrCreateFileID(HeaderFile
, clang::SrcMgr::C_User
));
510 auto BarFID
= SourceMgr
.getOrCreateFileID(BarFile
, clang::SrcMgr::C_User
);
511 IncFID
= SourceMgr
.getDecomposedIncludedLoc(FooFID
).first
;
512 // Check that includer is bar.h during this run.
513 EXPECT_EQ(IncFID
, BarFID
);
516 TEST_F(SourceManagerTest
, getMacroArgExpandedLocation
) {
518 "#define FM(x,y) x\n";
521 "#include \"/test-header.h\"\n"
526 "#define CONCAT(X, Y) X##Y\n"
529 std::unique_ptr
<llvm::MemoryBuffer
> HeaderBuf
=
530 llvm::MemoryBuffer::getMemBuffer(header
);
531 std::unique_ptr
<llvm::MemoryBuffer
> MainBuf
=
532 llvm::MemoryBuffer::getMemBuffer(main
);
533 FileID mainFileID
= SourceMgr
.createFileID(std::move(MainBuf
));
534 SourceMgr
.setMainFileID(mainFileID
);
536 FileEntryRef headerFile
= FileMgr
.getVirtualFileRef(
537 "/test-header.h", HeaderBuf
->getBufferSize(), 0);
538 SourceMgr
.overrideFileContents(headerFile
, std::move(HeaderBuf
));
540 TrivialModuleLoader ModLoader
;
541 HeaderSearch
HeaderInfo(std::make_shared
<HeaderSearchOptions
>(), SourceMgr
,
542 Diags
, LangOpts
, &*Target
);
544 Preprocessor
PP(std::make_shared
<PreprocessorOptions
>(), Diags
, LangOpts
,
545 SourceMgr
, HeaderInfo
, ModLoader
,
546 /*IILookup =*/nullptr,
547 /*OwnsHeaderSearch =*/false);
548 // Ensure we can get expanded locations in presence of implicit includes.
549 // These are different than normal includes since predefines buffer doesn't
550 // have a valid insertion location.
551 PP
.setPredefines("#include \"/implicit-header.h\"");
552 FileMgr
.getVirtualFileRef("/implicit-header.h", 0, 0);
553 PP
.Initialize(*Target
);
554 PP
.EnterMainSourceFile();
556 std::vector
<Token
> toks
;
557 PP
.LexTokensUntilEOF(&toks
);
559 // Make sure we got the tokens that we expected.
560 ASSERT_EQ(4U, toks
.size());
561 ASSERT_EQ(tok::numeric_constant
, toks
[0].getKind());
562 ASSERT_EQ(tok::numeric_constant
, toks
[1].getKind());
563 ASSERT_EQ(tok::numeric_constant
, toks
[2].getKind());
564 ASSERT_EQ(tok::numeric_constant
, toks
[3].getKind());
566 SourceLocation defLoc
= SourceMgr
.translateLineCol(mainFileID
, 2, 13);
567 SourceLocation loc1
= SourceMgr
.translateLineCol(mainFileID
, 3, 8);
568 SourceLocation loc2
= SourceMgr
.translateLineCol(mainFileID
, 4, 4);
569 SourceLocation loc3
= SourceMgr
.translateLineCol(mainFileID
, 5, 7);
570 SourceLocation defLoc2
= SourceMgr
.translateLineCol(mainFileID
, 6, 22);
571 defLoc
= SourceMgr
.getMacroArgExpandedLocation(defLoc
);
572 loc1
= SourceMgr
.getMacroArgExpandedLocation(loc1
);
573 loc2
= SourceMgr
.getMacroArgExpandedLocation(loc2
);
574 loc3
= SourceMgr
.getMacroArgExpandedLocation(loc3
);
575 defLoc2
= SourceMgr
.getMacroArgExpandedLocation(defLoc2
);
577 EXPECT_TRUE(defLoc
.isFileID());
578 EXPECT_TRUE(loc1
.isFileID());
579 EXPECT_TRUE(SourceMgr
.isMacroArgExpansion(loc2
));
580 EXPECT_TRUE(SourceMgr
.isMacroArgExpansion(loc3
));
581 EXPECT_EQ(loc2
, toks
[1].getLocation());
582 EXPECT_EQ(loc3
, toks
[2].getLocation());
583 EXPECT_TRUE(defLoc2
.isFileID());
589 enum Kind
{ kExpansion
, kDefinition
, kUnDefinition
};
593 LLVM_PREFERRED_TYPE(Kind
)
596 MacroAction(SourceLocation Loc
, StringRef Name
, unsigned K
)
597 : Loc(Loc
), Name(std::string(Name
)), MAKind(K
) {}
599 bool isExpansion() const { return MAKind
== kExpansion
; }
600 bool isDefinition() const { return MAKind
& kDefinition
; }
601 bool isUnDefinition() const { return MAKind
& kUnDefinition
; }
604 class MacroTracker
: public PPCallbacks
{
605 std::vector
<MacroAction
> &Macros
;
608 explicit MacroTracker(std::vector
<MacroAction
> &Macros
) : Macros(Macros
) { }
610 void MacroDefined(const Token
&MacroNameTok
,
611 const MacroDirective
*MD
) override
{
612 Macros
.push_back(MacroAction(MD
->getLocation(),
613 MacroNameTok
.getIdentifierInfo()->getName(),
614 MacroAction::kDefinition
));
616 void MacroUndefined(const Token
&MacroNameTok
,
617 const MacroDefinition
&MD
,
618 const MacroDirective
*UD
) override
{
620 MacroAction(UD
? UD
->getLocation() : SourceLocation(),
621 MacroNameTok
.getIdentifierInfo()->getName(),
622 UD
? MacroAction::kDefinition
| MacroAction::kUnDefinition
623 : MacroAction::kUnDefinition
));
625 void MacroExpands(const Token
&MacroNameTok
, const MacroDefinition
&MD
,
626 SourceRange Range
, const MacroArgs
*Args
) override
{
627 Macros
.push_back(MacroAction(MacroNameTok
.getLocation(),
628 MacroNameTok
.getIdentifierInfo()->getName(),
629 MacroAction::kExpansion
));
635 TEST_F(SourceManagerTest
, isBeforeInTranslationUnitWithMacroInInclude
) {
637 "#define MACRO_IN_INCLUDE 0\n"
638 "#define MACRO_DEFINED\n"
639 "#undef MACRO_DEFINED\n"
640 "#undef MACRO_UNDEFINED\n";
644 "#define INC \"/test-header.h\"\n"
646 "#define INC2 </test-header.h>\n"
647 "#include M(INC2)\n";
649 std::unique_ptr
<llvm::MemoryBuffer
> HeaderBuf
=
650 llvm::MemoryBuffer::getMemBuffer(header
);
651 std::unique_ptr
<llvm::MemoryBuffer
> MainBuf
=
652 llvm::MemoryBuffer::getMemBuffer(main
);
653 SourceMgr
.setMainFileID(SourceMgr
.createFileID(std::move(MainBuf
)));
655 FileEntryRef headerFile
= FileMgr
.getVirtualFileRef(
656 "/test-header.h", HeaderBuf
->getBufferSize(), 0);
657 SourceMgr
.overrideFileContents(headerFile
, std::move(HeaderBuf
));
659 TrivialModuleLoader ModLoader
;
660 HeaderSearch
HeaderInfo(std::make_shared
<HeaderSearchOptions
>(), SourceMgr
,
661 Diags
, LangOpts
, &*Target
);
662 Preprocessor
PP(std::make_shared
<PreprocessorOptions
>(), Diags
, LangOpts
,
663 SourceMgr
, HeaderInfo
, ModLoader
,
664 /*IILookup =*/nullptr,
665 /*OwnsHeaderSearch =*/false);
666 PP
.Initialize(*Target
);
668 std::vector
<MacroAction
> Macros
;
669 PP
.addPPCallbacks(std::make_unique
<MacroTracker
>(Macros
));
671 PP
.EnterMainSourceFile();
673 std::vector
<Token
> toks
;
674 PP
.LexTokensUntilEOF(&toks
);
676 // Make sure we got the tokens that we expected.
677 ASSERT_EQ(0U, toks
.size());
679 ASSERT_EQ(15U, Macros
.size());
681 ASSERT_TRUE(Macros
[0].isDefinition());
682 ASSERT_EQ("M", Macros
[0].Name
);
683 // #define INC "/test-header.h"
684 ASSERT_TRUE(Macros
[1].isDefinition());
685 ASSERT_EQ("INC", Macros
[1].Name
);
686 // M expansion in #include M(INC)
687 ASSERT_FALSE(Macros
[2].isDefinition());
688 ASSERT_EQ("M", Macros
[2].Name
);
689 // INC expansion in #include M(INC)
690 ASSERT_TRUE(Macros
[3].isExpansion());
691 ASSERT_EQ("INC", Macros
[3].Name
);
692 // #define MACRO_IN_INCLUDE 0
693 ASSERT_TRUE(Macros
[4].isDefinition());
694 ASSERT_EQ("MACRO_IN_INCLUDE", Macros
[4].Name
);
695 // #define MACRO_DEFINED
696 ASSERT_TRUE(Macros
[5].isDefinition());
697 ASSERT_FALSE(Macros
[5].isUnDefinition());
698 ASSERT_EQ("MACRO_DEFINED", Macros
[5].Name
);
699 // #undef MACRO_DEFINED
700 ASSERT_TRUE(Macros
[6].isDefinition());
701 ASSERT_TRUE(Macros
[6].isUnDefinition());
702 ASSERT_EQ("MACRO_DEFINED", Macros
[6].Name
);
703 // #undef MACRO_UNDEFINED
704 ASSERT_FALSE(Macros
[7].isDefinition());
705 ASSERT_TRUE(Macros
[7].isUnDefinition());
706 ASSERT_EQ("MACRO_UNDEFINED", Macros
[7].Name
);
707 // #define INC2 </test-header.h>
708 ASSERT_TRUE(Macros
[8].isDefinition());
709 ASSERT_EQ("INC2", Macros
[8].Name
);
710 // M expansion in #include M(INC2)
711 ASSERT_FALSE(Macros
[9].isDefinition());
712 ASSERT_EQ("M", Macros
[9].Name
);
713 // INC2 expansion in #include M(INC2)
714 ASSERT_TRUE(Macros
[10].isExpansion());
715 ASSERT_EQ("INC2", Macros
[10].Name
);
716 // #define MACRO_IN_INCLUDE 0
717 ASSERT_TRUE(Macros
[11].isDefinition());
718 ASSERT_EQ("MACRO_IN_INCLUDE", Macros
[11].Name
);
720 // The INC expansion in #include M(INC) comes before the first
721 // MACRO_IN_INCLUDE definition of the included file.
722 EXPECT_TRUE(SourceMgr
.isBeforeInTranslationUnit(Macros
[3].Loc
, Macros
[4].Loc
));
724 // The INC2 expansion in #include M(INC2) comes before the second
725 // MACRO_IN_INCLUDE definition of the included file.
726 EXPECT_TRUE(SourceMgr
.isBeforeInTranslationUnit(Macros
[10].Loc
, Macros
[11].Loc
));
729 TEST_F(SourceManagerTest
, isMainFile
) {
730 const char *Source
= "int x;";
732 std::unique_ptr
<llvm::MemoryBuffer
> Buf
=
733 llvm::MemoryBuffer::getMemBuffer(Source
);
734 FileEntryRef SourceFile
=
735 FileMgr
.getVirtualFileRef("mainFile.cpp", Buf
->getBufferSize(), 0);
736 SourceMgr
.overrideFileContents(SourceFile
, std::move(Buf
));
738 std::unique_ptr
<llvm::MemoryBuffer
> Buf2
=
739 llvm::MemoryBuffer::getMemBuffer(Source
);
740 FileEntryRef SecondFile
=
741 FileMgr
.getVirtualFileRef("file2.cpp", Buf2
->getBufferSize(), 0);
742 SourceMgr
.overrideFileContents(SecondFile
, std::move(Buf2
));
744 FileID MainFileID
= SourceMgr
.getOrCreateFileID(SourceFile
, SrcMgr::C_User
);
745 SourceMgr
.setMainFileID(MainFileID
);
747 EXPECT_TRUE(SourceMgr
.isMainFile(*SourceFile
));
748 EXPECT_TRUE(SourceMgr
.isMainFile(*SourceFile
));
749 EXPECT_FALSE(SourceMgr
.isMainFile(*SecondFile
));
754 } // anonymous namespace