Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / clang / unittests / Lex / HeaderSearchTest.cpp
blobc578fa72c859e0806367d5fdc0701464a64a0b78
1 //===- unittests/Lex/HeaderSearchTest.cpp ------ HeaderSearch 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 //===----------------------------------------------------------------------===//
9 #include "clang/Lex/HeaderSearch.h"
10 #include "HeaderMapTestUtils.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/SourceManager.h"
16 #include "clang/Basic/TargetInfo.h"
17 #include "clang/Basic/TargetOptions.h"
18 #include "clang/Lex/HeaderSearchOptions.h"
19 #include "clang/Serialization/InMemoryModuleCache.h"
20 #include "llvm/Support/MemoryBuffer.h"
21 #include "gtest/gtest.h"
23 namespace clang {
24 namespace {
26 // The test fixture.
27 class HeaderSearchTest : public ::testing::Test {
28 protected:
29 HeaderSearchTest()
30 : VFS(new llvm::vfs::InMemoryFileSystem), FileMgr(FileMgrOpts, VFS),
31 DiagID(new DiagnosticIDs()),
32 Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
33 SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions),
34 Search(std::make_shared<HeaderSearchOptions>(), SourceMgr, Diags,
35 LangOpts, Target.get()) {
36 TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
37 Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
40 void addSearchDir(llvm::StringRef Dir) {
41 VFS->addFile(
42 Dir, 0, llvm::MemoryBuffer::getMemBuffer(""), /*User=*/std::nullopt,
43 /*Group=*/std::nullopt, llvm::sys::fs::file_type::directory_file);
44 auto DE = FileMgr.getOptionalDirectoryRef(Dir);
45 assert(DE);
46 auto DL = DirectoryLookup(*DE, SrcMgr::C_User, /*isFramework=*/false);
47 Search.AddSearchPath(DL, /*isAngled=*/false);
50 void addFrameworkSearchDir(llvm::StringRef Dir, bool IsSystem = true) {
51 VFS->addFile(
52 Dir, 0, llvm::MemoryBuffer::getMemBuffer(""), /*User=*/std::nullopt,
53 /*Group=*/std::nullopt, llvm::sys::fs::file_type::directory_file);
54 auto DE = FileMgr.getOptionalDirectoryRef(Dir);
55 assert(DE);
56 auto DL = DirectoryLookup(*DE, IsSystem ? SrcMgr::C_System : SrcMgr::C_User,
57 /*isFramework=*/true);
58 if (IsSystem)
59 Search.AddSystemSearchPath(DL);
60 else
61 Search.AddSearchPath(DL, /*isAngled=*/true);
64 void addHeaderMap(llvm::StringRef Filename,
65 std::unique_ptr<llvm::MemoryBuffer> Buf,
66 bool isAngled = false) {
67 VFS->addFile(Filename, 0, std::move(Buf), /*User=*/std::nullopt,
68 /*Group=*/std::nullopt,
69 llvm::sys::fs::file_type::regular_file);
70 auto FE = FileMgr.getOptionalFileRef(Filename, true);
71 assert(FE);
73 // Test class supports only one HMap at a time.
74 assert(!HMap);
75 HMap = HeaderMap::Create(*FE, FileMgr);
76 auto DL =
77 DirectoryLookup(HMap.get(), SrcMgr::C_User, /*isFramework=*/false);
78 Search.AddSearchPath(DL, isAngled);
81 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS;
82 FileSystemOptions FileMgrOpts;
83 FileManager FileMgr;
84 IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
85 DiagnosticsEngine Diags;
86 SourceManager SourceMgr;
87 LangOptions LangOpts;
88 std::shared_ptr<TargetOptions> TargetOpts;
89 IntrusiveRefCntPtr<TargetInfo> Target;
90 HeaderSearch Search;
91 std::unique_ptr<HeaderMap> HMap;
94 TEST_F(HeaderSearchTest, NoSearchDir) {
95 EXPECT_EQ(Search.search_dir_size(), 0u);
96 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/x/y/z", /*WorkingDir=*/"",
97 /*MainFile=*/""),
98 "/x/y/z");
101 TEST_F(HeaderSearchTest, SimpleShorten) {
102 addSearchDir("/x");
103 addSearchDir("/x/y");
104 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/x/y/z", /*WorkingDir=*/"",
105 /*MainFile=*/""),
106 "z");
107 addSearchDir("/a/b/");
108 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/a/b/c", /*WorkingDir=*/"",
109 /*MainFile=*/""),
110 "c");
113 TEST_F(HeaderSearchTest, ShortenWithWorkingDir) {
114 addSearchDir("x/y");
115 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/a/b/c/x/y/z",
116 /*WorkingDir=*/"/a/b/c",
117 /*MainFile=*/""),
118 "z");
121 TEST_F(HeaderSearchTest, Dots) {
122 addSearchDir("/x/./y/");
123 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/x/y/./z",
124 /*WorkingDir=*/"",
125 /*MainFile=*/""),
126 "z");
127 addSearchDir("a/.././c/");
128 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/m/n/./c/z",
129 /*WorkingDir=*/"/m/n/",
130 /*MainFile=*/""),
131 "z");
134 #ifdef _WIN32
135 TEST_F(HeaderSearchTest, BackSlash) {
136 addSearchDir("C:\\x\\y\\");
137 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("C:\\x\\y\\z\\t",
138 /*WorkingDir=*/"",
139 /*MainFile=*/""),
140 "z/t");
143 TEST_F(HeaderSearchTest, BackSlashWithDotDot) {
144 addSearchDir("..\\y");
145 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("C:\\x\\y\\z\\t",
146 /*WorkingDir=*/"C:/x/y/",
147 /*MainFile=*/""),
148 "z/t");
150 #endif
152 TEST_F(HeaderSearchTest, DotDotsWithAbsPath) {
153 addSearchDir("/x/../y/");
154 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/y/z",
155 /*WorkingDir=*/"",
156 /*MainFile=*/""),
157 "z");
160 TEST_F(HeaderSearchTest, BothDotDots) {
161 addSearchDir("/x/../y/");
162 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/x/../y/z",
163 /*WorkingDir=*/"",
164 /*MainFile=*/""),
165 "z");
168 TEST_F(HeaderSearchTest, IncludeFromSameDirectory) {
169 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/y/z/t.h",
170 /*WorkingDir=*/"",
171 /*MainFile=*/"/y/a.cc"),
172 "z/t.h");
174 addSearchDir("/");
175 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/y/z/t.h",
176 /*WorkingDir=*/"",
177 /*MainFile=*/"/y/a.cc"),
178 "y/z/t.h");
181 TEST_F(HeaderSearchTest, SdkFramework) {
182 addFrameworkSearchDir(
183 "/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.3.sdk/Frameworks/");
184 bool IsAngled = false;
185 EXPECT_EQ(Search.suggestPathToFileForDiagnostics(
186 "/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/"
187 "Frameworks/AppKit.framework/Headers/NSView.h",
188 /*WorkingDir=*/"",
189 /*MainFile=*/"", &IsAngled),
190 "AppKit/NSView.h");
191 EXPECT_TRUE(IsAngled);
193 addFrameworkSearchDir("/System/Developer/Library/Framworks/",
194 /*IsSystem*/ false);
195 EXPECT_EQ(Search.suggestPathToFileForDiagnostics(
196 "/System/Developer/Library/Framworks/"
197 "Foo.framework/Headers/Foo.h",
198 /*WorkingDir=*/"",
199 /*MainFile=*/"", &IsAngled),
200 "Foo/Foo.h");
201 // Expect to be true even though we passed false to IsSystem earlier since
202 // all frameworks should be treated as <>.
203 EXPECT_TRUE(IsAngled);
206 TEST_F(HeaderSearchTest, NestedFramework) {
207 addFrameworkSearchDir("/Platforms/MacOSX/Frameworks");
208 EXPECT_EQ(Search.suggestPathToFileForDiagnostics(
209 "/Platforms/MacOSX/Frameworks/AppKit.framework/Frameworks/"
210 "Sub.framework/Headers/Sub.h",
211 /*WorkingDir=*/"",
212 /*MainFile=*/""),
213 "Sub/Sub.h");
216 TEST_F(HeaderSearchTest, HeaderFrameworkLookup) {
217 std::string HeaderPath = "/tmp/Frameworks/Foo.framework/Headers/Foo.h";
218 addFrameworkSearchDir("/tmp/Frameworks");
219 VFS->addFile(HeaderPath, 0,
220 llvm::MemoryBuffer::getMemBufferCopy("", HeaderPath),
221 /*User=*/std::nullopt, /*Group=*/std::nullopt,
222 llvm::sys::fs::file_type::regular_file);
224 bool IsFrameworkFound = false;
225 auto FoundFile = Search.LookupFile(
226 "Foo/Foo.h", SourceLocation(), /*isAngled=*/true, /*FromDir=*/nullptr,
227 /*CurDir=*/nullptr, /*Includers=*/{}, /*SearchPath=*/nullptr,
228 /*RelativePath=*/nullptr, /*RequestingModule=*/nullptr,
229 /*SuggestedModule=*/nullptr, /*IsMapped=*/nullptr, &IsFrameworkFound);
231 EXPECT_TRUE(FoundFile.has_value());
232 EXPECT_TRUE(IsFrameworkFound);
233 auto &FE = *FoundFile;
234 auto FI = Search.getExistingFileInfo(FE);
235 EXPECT_TRUE(FI);
236 EXPECT_TRUE(FI->IsValid);
237 EXPECT_EQ(FI->Framework.str(), "Foo");
238 EXPECT_EQ(Search.getIncludeNameForHeader(FE), "Foo/Foo.h");
241 // Helper struct with null terminator character to make MemoryBuffer happy.
242 template <class FileTy, class PaddingTy>
243 struct NullTerminatedFile : public FileTy {
244 PaddingTy Padding = 0;
247 TEST_F(HeaderSearchTest, HeaderMapReverseLookup) {
248 typedef NullTerminatedFile<test::HMapFileMock<2, 32>, char> FileTy;
249 FileTy File;
250 File.init();
252 test::HMapFileMockMaker<FileTy> Maker(File);
253 auto a = Maker.addString("d.h");
254 auto b = Maker.addString("b/");
255 auto c = Maker.addString("c.h");
256 Maker.addBucket("d.h", a, b, c);
258 addHeaderMap("/x/y/z.hmap", File.getBuffer());
259 addSearchDir("/a");
261 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/a/b/c.h",
262 /*WorkingDir=*/"",
263 /*MainFile=*/""),
264 "d.h");
267 TEST_F(HeaderSearchTest, HeaderMapFrameworkLookup) {
268 typedef NullTerminatedFile<test::HMapFileMock<4, 128>, char> FileTy;
269 FileTy File;
270 File.init();
272 std::string HeaderDirName = "/tmp/Sources/Foo/Headers/";
273 std::string HeaderName = "Foo.h";
274 if (is_style_windows(llvm::sys::path::Style::native)) {
275 // Force header path to be absolute on windows.
276 // As headermap content should represent absolute locations.
277 HeaderDirName = "C:" + HeaderDirName;
280 test::HMapFileMockMaker<FileTy> Maker(File);
281 auto a = Maker.addString("Foo/Foo.h");
282 auto b = Maker.addString(HeaderDirName);
283 auto c = Maker.addString(HeaderName);
284 Maker.addBucket("Foo/Foo.h", a, b, c);
285 addHeaderMap("product-headers.hmap", File.getBuffer(), /*isAngled=*/true);
287 VFS->addFile(
288 HeaderDirName + HeaderName, 0,
289 llvm::MemoryBuffer::getMemBufferCopy("", HeaderDirName + HeaderName),
290 /*User=*/std::nullopt, /*Group=*/std::nullopt,
291 llvm::sys::fs::file_type::regular_file);
293 bool IsMapped = false;
294 auto FoundFile = Search.LookupFile(
295 "Foo/Foo.h", SourceLocation(), /*isAngled=*/true, /*FromDir=*/nullptr,
296 /*CurDir=*/nullptr, /*Includers=*/{}, /*SearchPath=*/nullptr,
297 /*RelativePath=*/nullptr, /*RequestingModule=*/nullptr,
298 /*SuggestedModule=*/nullptr, &IsMapped,
299 /*IsFrameworkFound=*/nullptr);
301 EXPECT_TRUE(FoundFile.has_value());
302 EXPECT_TRUE(IsMapped);
303 auto &FE = *FoundFile;
304 auto FI = Search.getExistingFileInfo(FE);
305 EXPECT_TRUE(FI);
306 EXPECT_TRUE(FI->IsValid);
307 EXPECT_EQ(FI->Framework.str(), "Foo");
308 EXPECT_EQ(Search.getIncludeNameForHeader(FE), "Foo/Foo.h");
311 } // namespace
312 } // namespace clang