[TableGen] Fix validateOperandClass for non Phyical Reg (#118146)
[llvm-project.git] / clang / unittests / Lex / HeaderSearchTest.cpp
blob4d07150c04e8d4342ccca65f5e2efce352a76adc
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"
22 #include <memory>
23 #include <string>
25 namespace clang {
26 namespace {
28 // The test fixture.
29 class HeaderSearchTest : public ::testing::Test {
30 protected:
31 HeaderSearchTest()
32 : VFS(new llvm::vfs::InMemoryFileSystem), FileMgr(FileMgrOpts, VFS),
33 DiagID(new DiagnosticIDs()),
34 Diags(DiagID, new DiagnosticOptions, new IgnoringDiagConsumer()),
35 SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions),
36 Search(std::make_shared<HeaderSearchOptions>(), SourceMgr, Diags,
37 LangOpts, Target.get()) {
38 TargetOpts->Triple = "x86_64-apple-darwin11.1.0";
39 Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
42 void addSearchDir(llvm::StringRef Dir) {
43 VFS->addFile(
44 Dir, 0, llvm::MemoryBuffer::getMemBuffer(""), /*User=*/std::nullopt,
45 /*Group=*/std::nullopt, llvm::sys::fs::file_type::directory_file);
46 auto DE = FileMgr.getOptionalDirectoryRef(Dir);
47 assert(DE);
48 auto DL = DirectoryLookup(*DE, SrcMgr::C_User, /*isFramework=*/false);
49 Search.AddSearchPath(DL, /*isAngled=*/false);
52 void addFrameworkSearchDir(llvm::StringRef Dir, bool IsSystem = true) {
53 VFS->addFile(
54 Dir, 0, llvm::MemoryBuffer::getMemBuffer(""), /*User=*/std::nullopt,
55 /*Group=*/std::nullopt, llvm::sys::fs::file_type::directory_file);
56 auto DE = FileMgr.getOptionalDirectoryRef(Dir);
57 assert(DE);
58 auto DL = DirectoryLookup(*DE, IsSystem ? SrcMgr::C_System : SrcMgr::C_User,
59 /*isFramework=*/true);
60 if (IsSystem)
61 Search.AddSystemSearchPath(DL);
62 else
63 Search.AddSearchPath(DL, /*isAngled=*/true);
66 void addHeaderMap(llvm::StringRef Filename,
67 std::unique_ptr<llvm::MemoryBuffer> Buf,
68 bool isAngled = false) {
69 VFS->addFile(Filename, 0, std::move(Buf), /*User=*/std::nullopt,
70 /*Group=*/std::nullopt,
71 llvm::sys::fs::file_type::regular_file);
72 auto FE = FileMgr.getOptionalFileRef(Filename, true);
73 assert(FE);
75 // Test class supports only one HMap at a time.
76 assert(!HMap);
77 HMap = HeaderMap::Create(*FE, FileMgr);
78 auto DL = DirectoryLookup(HMap.get(), SrcMgr::C_User);
79 Search.AddSearchPath(DL, isAngled);
82 IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS;
83 FileSystemOptions FileMgrOpts;
84 FileManager FileMgr;
85 IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
86 DiagnosticsEngine Diags;
87 SourceManager SourceMgr;
88 LangOptions LangOpts;
89 std::shared_ptr<TargetOptions> TargetOpts;
90 IntrusiveRefCntPtr<TargetInfo> Target;
91 HeaderSearch Search;
92 std::unique_ptr<HeaderMap> HMap;
95 TEST_F(HeaderSearchTest, NoSearchDir) {
96 EXPECT_EQ(Search.search_dir_size(), 0u);
97 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/x/y/z", /*WorkingDir=*/"",
98 /*MainFile=*/""),
99 "/x/y/z");
102 TEST_F(HeaderSearchTest, SimpleShorten) {
103 addSearchDir("/x");
104 addSearchDir("/x/y");
105 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/x/y/z", /*WorkingDir=*/"",
106 /*MainFile=*/""),
107 "z");
108 addSearchDir("/a/b/");
109 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/a/b/c", /*WorkingDir=*/"",
110 /*MainFile=*/""),
111 "c");
114 TEST_F(HeaderSearchTest, ShortenWithWorkingDir) {
115 addSearchDir("x/y");
116 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/a/b/c/x/y/z",
117 /*WorkingDir=*/"/a/b/c",
118 /*MainFile=*/""),
119 "z");
122 TEST_F(HeaderSearchTest, Dots) {
123 addSearchDir("/x/./y/");
124 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/x/y/./z",
125 /*WorkingDir=*/"",
126 /*MainFile=*/""),
127 "z");
128 addSearchDir("a/.././c/");
129 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/m/n/./c/z",
130 /*WorkingDir=*/"/m/n/",
131 /*MainFile=*/""),
132 "z");
135 TEST_F(HeaderSearchTest, RelativeDirs) {
136 ASSERT_FALSE(VFS->setCurrentWorkingDirectory("/root/some/dir"));
137 addSearchDir("..");
138 EXPECT_EQ(
139 Search.suggestPathToFileForDiagnostics("/root/some/foo.h",
140 /*WorkingDir=*/"/root/some/dir",
141 /*MainFile=*/""),
142 "foo.h");
143 EXPECT_EQ(
144 Search.suggestPathToFileForDiagnostics("../foo.h",
145 /*WorkingDir=*/"/root/some/dir",
146 /*MainFile=*/""),
147 "foo.h");
150 #ifdef _WIN32
151 TEST_F(HeaderSearchTest, BackSlash) {
152 addSearchDir("C:\\x\\y\\");
153 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("C:\\x\\y\\z\\t",
154 /*WorkingDir=*/"",
155 /*MainFile=*/""),
156 "z/t");
159 TEST_F(HeaderSearchTest, BackSlashWithDotDot) {
160 addSearchDir("..\\y");
161 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("C:\\x\\y\\z\\t",
162 /*WorkingDir=*/"C:/x/y/",
163 /*MainFile=*/""),
164 "z/t");
166 #endif
168 TEST_F(HeaderSearchTest, DotDotsWithAbsPath) {
169 addSearchDir("/x/../y/");
170 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/y/z",
171 /*WorkingDir=*/"",
172 /*MainFile=*/""),
173 "z");
176 TEST_F(HeaderSearchTest, BothDotDots) {
177 addSearchDir("/x/../y/");
178 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/x/../y/z",
179 /*WorkingDir=*/"",
180 /*MainFile=*/""),
181 "z");
184 TEST_F(HeaderSearchTest, IncludeFromSameDirectory) {
185 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/y/z/t.h",
186 /*WorkingDir=*/"",
187 /*MainFile=*/"/y/a.cc"),
188 "z/t.h");
190 addSearchDir("/");
191 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/y/z/t.h",
192 /*WorkingDir=*/"",
193 /*MainFile=*/"/y/a.cc"),
194 "y/z/t.h");
197 TEST_F(HeaderSearchTest, SdkFramework) {
198 addFrameworkSearchDir(
199 "/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.3.sdk/Frameworks/");
200 bool IsAngled = false;
201 EXPECT_EQ(Search.suggestPathToFileForDiagnostics(
202 "/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/"
203 "Frameworks/AppKit.framework/Headers/NSView.h",
204 /*WorkingDir=*/"",
205 /*MainFile=*/"", &IsAngled),
206 "AppKit/NSView.h");
207 EXPECT_TRUE(IsAngled);
209 addFrameworkSearchDir("/System/Developer/Library/Framworks/",
210 /*IsSystem*/ false);
211 EXPECT_EQ(Search.suggestPathToFileForDiagnostics(
212 "/System/Developer/Library/Framworks/"
213 "Foo.framework/Headers/Foo.h",
214 /*WorkingDir=*/"",
215 /*MainFile=*/"", &IsAngled),
216 "Foo/Foo.h");
217 // Expect to be true even though we passed false to IsSystem earlier since
218 // all frameworks should be treated as <>.
219 EXPECT_TRUE(IsAngled);
222 TEST_F(HeaderSearchTest, NestedFramework) {
223 addFrameworkSearchDir("/Platforms/MacOSX/Frameworks");
224 EXPECT_EQ(Search.suggestPathToFileForDiagnostics(
225 "/Platforms/MacOSX/Frameworks/AppKit.framework/Frameworks/"
226 "Sub.framework/Headers/Sub.h",
227 /*WorkingDir=*/"",
228 /*MainFile=*/""),
229 "Sub/Sub.h");
232 TEST_F(HeaderSearchTest, HeaderFrameworkLookup) {
233 std::string HeaderPath = "/tmp/Frameworks/Foo.framework/Headers/Foo.h";
234 addFrameworkSearchDir("/tmp/Frameworks");
235 VFS->addFile(HeaderPath, 0,
236 llvm::MemoryBuffer::getMemBufferCopy("", HeaderPath),
237 /*User=*/std::nullopt, /*Group=*/std::nullopt,
238 llvm::sys::fs::file_type::regular_file);
240 bool IsFrameworkFound = false;
241 auto FoundFile = Search.LookupFile(
242 "Foo/Foo.h", SourceLocation(), /*isAngled=*/true, /*FromDir=*/nullptr,
243 /*CurDir=*/nullptr, /*Includers=*/{}, /*SearchPath=*/nullptr,
244 /*RelativePath=*/nullptr, /*RequestingModule=*/nullptr,
245 /*SuggestedModule=*/nullptr, /*IsMapped=*/nullptr, &IsFrameworkFound);
247 EXPECT_TRUE(FoundFile.has_value());
248 EXPECT_TRUE(IsFrameworkFound);
249 auto &FE = *FoundFile;
250 auto FI = Search.getExistingFileInfo(FE);
251 EXPECT_TRUE(FI);
252 EXPECT_TRUE(FI->IsValid);
253 EXPECT_EQ(Search.getIncludeNameForHeader(FE), "Foo/Foo.h");
256 // Helper struct with null terminator character to make MemoryBuffer happy.
257 template <class FileTy, class PaddingTy>
258 struct NullTerminatedFile : public FileTy {
259 PaddingTy Padding = 0;
262 TEST_F(HeaderSearchTest, HeaderMapReverseLookup) {
263 typedef NullTerminatedFile<test::HMapFileMock<2, 32>, char> FileTy;
264 FileTy File;
265 File.init();
267 test::HMapFileMockMaker<FileTy> Maker(File);
268 auto a = Maker.addString("d.h");
269 auto b = Maker.addString("b/");
270 auto c = Maker.addString("c.h");
271 Maker.addBucket("d.h", a, b, c);
273 addHeaderMap("/x/y/z.hmap", File.getBuffer());
274 addSearchDir("/a");
276 EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/a/b/c.h",
277 /*WorkingDir=*/"",
278 /*MainFile=*/""),
279 "d.h");
282 TEST_F(HeaderSearchTest, HeaderMapFrameworkLookup) {
283 typedef NullTerminatedFile<test::HMapFileMock<4, 128>, char> FileTy;
284 FileTy File;
285 File.init();
287 std::string HeaderDirName = "/tmp/Sources/Foo/Headers/";
288 std::string HeaderName = "Foo.h";
289 if (is_style_windows(llvm::sys::path::Style::native)) {
290 // Force header path to be absolute on windows.
291 // As headermap content should represent absolute locations.
292 HeaderDirName = "C:" + HeaderDirName;
295 test::HMapFileMockMaker<FileTy> Maker(File);
296 auto a = Maker.addString("Foo/Foo.h");
297 auto b = Maker.addString(HeaderDirName);
298 auto c = Maker.addString(HeaderName);
299 Maker.addBucket("Foo/Foo.h", a, b, c);
300 addHeaderMap("product-headers.hmap", File.getBuffer(), /*isAngled=*/true);
302 VFS->addFile(
303 HeaderDirName + HeaderName, 0,
304 llvm::MemoryBuffer::getMemBufferCopy("", HeaderDirName + HeaderName),
305 /*User=*/std::nullopt, /*Group=*/std::nullopt,
306 llvm::sys::fs::file_type::regular_file);
308 bool IsMapped = false;
309 auto FoundFile = Search.LookupFile(
310 "Foo/Foo.h", SourceLocation(), /*isAngled=*/true, /*FromDir=*/nullptr,
311 /*CurDir=*/nullptr, /*Includers=*/{}, /*SearchPath=*/nullptr,
312 /*RelativePath=*/nullptr, /*RequestingModule=*/nullptr,
313 /*SuggestedModule=*/nullptr, &IsMapped,
314 /*IsFrameworkFound=*/nullptr);
316 EXPECT_TRUE(FoundFile.has_value());
317 EXPECT_TRUE(IsMapped);
318 auto &FE = *FoundFile;
319 auto FI = Search.getExistingFileInfo(FE);
320 EXPECT_TRUE(FI);
321 EXPECT_TRUE(FI->IsValid);
322 EXPECT_EQ(Search.getIncludeNameForHeader(FE), "Foo/Foo.h");
325 TEST_F(HeaderSearchTest, HeaderFileInfoMerge) {
326 auto AddHeader = [&](std::string HeaderPath) -> FileEntryRef {
327 VFS->addFile(HeaderPath, 0,
328 llvm::MemoryBuffer::getMemBufferCopy("", HeaderPath),
329 /*User=*/std::nullopt, /*Group=*/std::nullopt,
330 llvm::sys::fs::file_type::regular_file);
331 return *FileMgr.getOptionalFileRef(HeaderPath);
334 class MockExternalHeaderFileInfoSource : public ExternalHeaderFileInfoSource {
335 HeaderFileInfo GetHeaderFileInfo(FileEntryRef FE) {
336 HeaderFileInfo HFI;
337 auto FileName = FE.getName();
338 if (FileName == ModularPath)
339 HFI.mergeModuleMembership(ModuleMap::NormalHeader);
340 else if (FileName == TextualPath)
341 HFI.mergeModuleMembership(ModuleMap::TextualHeader);
342 HFI.External = true;
343 HFI.IsValid = true;
344 return HFI;
347 public:
348 std::string ModularPath = "/modular.h";
349 std::string TextualPath = "/textual.h";
352 auto ExternalSource = std::make_unique<MockExternalHeaderFileInfoSource>();
353 Search.SetExternalSource(ExternalSource.get());
355 // Everything should start out external.
356 auto ModularFE = AddHeader(ExternalSource->ModularPath);
357 auto TextualFE = AddHeader(ExternalSource->TextualPath);
358 EXPECT_TRUE(Search.getExistingFileInfo(ModularFE)->External);
359 EXPECT_TRUE(Search.getExistingFileInfo(TextualFE)->External);
361 // Marking the same role should keep it external
362 Search.MarkFileModuleHeader(ModularFE, ModuleMap::NormalHeader,
363 /*isCompilingModuleHeader=*/false);
364 Search.MarkFileModuleHeader(TextualFE, ModuleMap::TextualHeader,
365 /*isCompilingModuleHeader=*/false);
366 EXPECT_TRUE(Search.getExistingFileInfo(ModularFE)->External);
367 EXPECT_TRUE(Search.getExistingFileInfo(TextualFE)->External);
369 // textual -> modular should update the HFI, but modular -> textual should be
370 // a no-op.
371 Search.MarkFileModuleHeader(ModularFE, ModuleMap::TextualHeader,
372 /*isCompilingModuleHeader=*/false);
373 Search.MarkFileModuleHeader(TextualFE, ModuleMap::NormalHeader,
374 /*isCompilingModuleHeader=*/false);
375 auto ModularFI = Search.getExistingFileInfo(ModularFE);
376 auto TextualFI = Search.getExistingFileInfo(TextualFE);
377 EXPECT_TRUE(ModularFI->External);
378 EXPECT_TRUE(ModularFI->isModuleHeader);
379 EXPECT_FALSE(ModularFI->isTextualModuleHeader);
380 EXPECT_FALSE(TextualFI->External);
381 EXPECT_TRUE(TextualFI->isModuleHeader);
382 EXPECT_FALSE(TextualFI->isTextualModuleHeader);
384 // Compiling the module should make the HFI local.
385 Search.MarkFileModuleHeader(ModularFE, ModuleMap::NormalHeader,
386 /*isCompilingModuleHeader=*/true);
387 Search.MarkFileModuleHeader(TextualFE, ModuleMap::NormalHeader,
388 /*isCompilingModuleHeader=*/true);
389 EXPECT_FALSE(Search.getExistingFileInfo(ModularFE)->External);
390 EXPECT_FALSE(Search.getExistingFileInfo(TextualFE)->External);
393 } // namespace
394 } // namespace clang