[docs] Add LICENSE.txt to the root of the mono-repo
[llvm-project.git] / clang / unittests / Lex / HeaderSearchTest.cpp
blob5024f0d3d6b00684c0901f9197e35beff5d381b2
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(Dir, 0, llvm::MemoryBuffer::getMemBuffer(""), /*User=*/None,
42 /*Group=*/None, llvm::sys::fs::file_type::directory_file);
43 auto DE = FileMgr.getOptionalDirectoryRef(Dir);
44 assert(DE);
45 auto DL = DirectoryLookup(*DE, SrcMgr::C_User, /*isFramework=*/false);
46 Search.AddSearchPath(DL, /*isAngled=*/false);
49 void addSystemFrameworkSearchDir(llvm::StringRef Dir) {
50 VFS->addFile(Dir, 0, llvm::MemoryBuffer::getMemBuffer(""), /*User=*/None,
51 /*Group=*/None, llvm::sys::fs::file_type::directory_file);
52 auto DE = FileMgr.getOptionalDirectoryRef(Dir);
53 assert(DE);
54 auto DL = DirectoryLookup(*DE, SrcMgr::C_System, /*isFramework=*/true);
55 Search.AddSystemSearchPath(DL);
58 void addHeaderMap(llvm::StringRef Filename,
59 std::unique_ptr<llvm::MemoryBuffer> Buf,
60 bool isAngled = false) {
61 VFS->addFile(Filename, 0, std::move(Buf), /*User=*/None, /*Group=*/None,
62 llvm::sys::fs::file_type::regular_file);
63 auto FE = FileMgr.getFile(Filename, true);
64 assert(FE);
66 // Test class supports only one HMap at a time.
67 assert(!HMap);
68 HMap = HeaderMap::Create(*FE, FileMgr);
69 auto DL =
70 DirectoryLookup(HMap.get(), SrcMgr::C_User, /*isFramework=*/false);
71 Search.AddSearchPath(DL, isAngled);
74 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS;
75 FileSystemOptions FileMgrOpts;
76 FileManager FileMgr;
77 IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
78 DiagnosticsEngine Diags;
79 SourceManager SourceMgr;
80 LangOptions LangOpts;
81 std::shared_ptr<TargetOptions> TargetOpts;
82 IntrusiveRefCntPtr<TargetInfo> Target;
83 HeaderSearch Search;
84 std::unique_ptr<HeaderMap> HMap;
87 TEST_F(HeaderSearchTest, NoSearchDir) {
88 EXPECT_EQ(Search.search_dir_size(), 0u);
89 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/x/y/z", /*WorkingDir=*/"",
90 /*MainFile=*/""),
91 "/x/y/z");
94 TEST_F(HeaderSearchTest, SimpleShorten) {
95 addSearchDir("/x");
96 addSearchDir("/x/y");
97 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/x/y/z", /*WorkingDir=*/"",
98 /*MainFile=*/""),
99 "z");
100 addSearchDir("/a/b/");
101 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/a/b/c", /*WorkingDir=*/"",
102 /*MainFile=*/""),
103 "c");
106 TEST_F(HeaderSearchTest, ShortenWithWorkingDir) {
107 addSearchDir("x/y");
108 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/a/b/c/x/y/z",
109 /*WorkingDir=*/"/a/b/c",
110 /*MainFile=*/""),
111 "z");
114 TEST_F(HeaderSearchTest, Dots) {
115 addSearchDir("/x/./y/");
116 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/x/y/./z",
117 /*WorkingDir=*/"",
118 /*MainFile=*/""),
119 "z");
120 addSearchDir("a/.././c/");
121 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/m/n/./c/z",
122 /*WorkingDir=*/"/m/n/",
123 /*MainFile=*/""),
124 "z");
127 #ifdef _WIN32
128 TEST_F(HeaderSearchTest, BackSlash) {
129 addSearchDir("C:\\x\\y\\");
130 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("C:\\x\\y\\z\\t",
131 /*WorkingDir=*/"",
132 /*MainFile=*/""),
133 "z/t");
136 TEST_F(HeaderSearchTest, BackSlashWithDotDot) {
137 addSearchDir("..\\y");
138 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("C:\\x\\y\\z\\t",
139 /*WorkingDir=*/"C:/x/y/",
140 /*MainFile=*/""),
141 "z/t");
143 #endif
145 TEST_F(HeaderSearchTest, DotDotsWithAbsPath) {
146 addSearchDir("/x/../y/");
147 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/y/z",
148 /*WorkingDir=*/"",
149 /*MainFile=*/""),
150 "z");
153 TEST_F(HeaderSearchTest, IncludeFromSameDirectory) {
154 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/y/z/t.h",
155 /*WorkingDir=*/"",
156 /*MainFile=*/"/y/a.cc"),
157 "z/t.h");
159 addSearchDir("/");
160 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/y/z/t.h",
161 /*WorkingDir=*/"",
162 /*MainFile=*/"/y/a.cc"),
163 "y/z/t.h");
166 TEST_F(HeaderSearchTest, SdkFramework) {
167 addSystemFrameworkSearchDir(
168 "/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.3.sdk/Frameworks/");
169 bool IsSystem = false;
170 EXPECT_EQ(Search.suggestPathToFileForDiagnostics(
171 "/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/"
172 "Frameworks/AppKit.framework/Headers/NSView.h",
173 /*WorkingDir=*/"",
174 /*MainFile=*/"", &IsSystem),
175 "AppKit/NSView.h");
176 EXPECT_TRUE(IsSystem);
179 TEST_F(HeaderSearchTest, NestedFramework) {
180 addSystemFrameworkSearchDir("/Platforms/MacOSX/Frameworks");
181 EXPECT_EQ(Search.suggestPathToFileForDiagnostics(
182 "/Platforms/MacOSX/Frameworks/AppKit.framework/Frameworks/"
183 "Sub.framework/Headers/Sub.h",
184 /*WorkingDir=*/"",
185 /*MainFile=*/""),
186 "Sub/Sub.h");
189 TEST_F(HeaderSearchTest, HeaderFrameworkLookup) {
190 std::string HeaderPath = "/tmp/Frameworks/Foo.framework/Headers/Foo.h";
191 addSystemFrameworkSearchDir("/tmp/Frameworks");
192 VFS->addFile(
193 HeaderPath, 0, llvm::MemoryBuffer::getMemBufferCopy("", HeaderPath),
194 /*User=*/None, /*Group=*/None, llvm::sys::fs::file_type::regular_file);
196 bool IsFrameworkFound = false;
197 auto FoundFile = Search.LookupFile(
198 "Foo/Foo.h", SourceLocation(), /*isAngled=*/true, /*FromDir=*/nullptr,
199 /*CurDir=*/nullptr, /*Includers=*/{}, /*SearchPath=*/nullptr,
200 /*RelativePath=*/nullptr, /*RequestingModule=*/nullptr,
201 /*SuggestedModule=*/nullptr, /*IsMapped=*/nullptr, &IsFrameworkFound);
203 EXPECT_TRUE(FoundFile.has_value());
204 EXPECT_TRUE(IsFrameworkFound);
205 auto &FE = FoundFile.value();
206 auto FI = Search.getExistingFileInfo(FE);
207 EXPECT_TRUE(FI);
208 EXPECT_TRUE(FI->IsValid);
209 EXPECT_EQ(FI->Framework.str(), "Foo");
210 EXPECT_EQ(Search.getIncludeNameForHeader(FE), "Foo/Foo.h");
213 // Helper struct with null terminator character to make MemoryBuffer happy.
214 template <class FileTy, class PaddingTy>
215 struct NullTerminatedFile : public FileTy {
216 PaddingTy Padding = 0;
219 TEST_F(HeaderSearchTest, HeaderMapReverseLookup) {
220 typedef NullTerminatedFile<test::HMapFileMock<2, 32>, char> FileTy;
221 FileTy File;
222 File.init();
224 test::HMapFileMockMaker<FileTy> Maker(File);
225 auto a = Maker.addString("d.h");
226 auto b = Maker.addString("b/");
227 auto c = Maker.addString("c.h");
228 Maker.addBucket("d.h", a, b, c);
230 addHeaderMap("/x/y/z.hmap", File.getBuffer());
231 addSearchDir("/a");
233 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/a/b/c.h",
234 /*WorkingDir=*/"",
235 /*MainFile=*/""),
236 "d.h");
239 TEST_F(HeaderSearchTest, HeaderMapFrameworkLookup) {
240 typedef NullTerminatedFile<test::HMapFileMock<4, 128>, char> FileTy;
241 FileTy File;
242 File.init();
244 std::string HeaderDirName = "/tmp/Sources/Foo/Headers/";
245 std::string HeaderName = "Foo.h";
246 if (is_style_windows(llvm::sys::path::Style::native)) {
247 // Force header path to be absolute on windows.
248 // As headermap content should represent absolute locations.
249 HeaderDirName = "C:" + HeaderDirName;
252 test::HMapFileMockMaker<FileTy> Maker(File);
253 auto a = Maker.addString("Foo/Foo.h");
254 auto b = Maker.addString(HeaderDirName);
255 auto c = Maker.addString(HeaderName);
256 Maker.addBucket("Foo/Foo.h", a, b, c);
257 addHeaderMap("product-headers.hmap", File.getBuffer(), /*isAngled=*/true);
259 VFS->addFile(
260 HeaderDirName + HeaderName, 0,
261 llvm::MemoryBuffer::getMemBufferCopy("", HeaderDirName + HeaderName),
262 /*User=*/None, /*Group=*/None, llvm::sys::fs::file_type::regular_file);
264 bool IsMapped = false;
265 auto FoundFile = Search.LookupFile(
266 "Foo/Foo.h", SourceLocation(), /*isAngled=*/true, /*FromDir=*/nullptr,
267 /*CurDir=*/nullptr, /*Includers=*/{}, /*SearchPath=*/nullptr,
268 /*RelativePath=*/nullptr, /*RequestingModule=*/nullptr,
269 /*SuggestedModule=*/nullptr, &IsMapped,
270 /*IsFrameworkFound=*/nullptr);
272 EXPECT_TRUE(FoundFile.has_value());
273 EXPECT_TRUE(IsMapped);
274 auto &FE = FoundFile.value();
275 auto FI = Search.getExistingFileInfo(FE);
276 EXPECT_TRUE(FI);
277 EXPECT_TRUE(FI->IsValid);
278 EXPECT_EQ(FI->Framework.str(), "Foo");
279 EXPECT_EQ(Search.getIncludeNameForHeader(FE), "Foo/Foo.h");
282 } // namespace
283 } // namespace clang