10#include "llvm/ADT/StringRef.h"
11#include "llvm/ADT/StringSwitch.h"
20 for (
const Library &Lib : Libraries)
21 llvm::append_range(Headers, Lib.Headers);
27 return scanForFrameworks(Directory);
29 return scanForUnwrappedLibraries(Directory);
32llvm::Error DirectoryScanner::scanForUnwrappedLibraries(StringRef Directory) {
36 sys::path::append(Path, Sub);
40 auto DirPublic = GetDirectory(
"usr/include");
41 auto DirPrivate = GetDirectory(
"usr/local/include");
42 if (!DirPublic && !DirPrivate) {
43 std::error_code ec = std::make_error_code(std::errc::not_a_directory);
44 return createStringError(ec,
45 "cannot find any public (usr/include) or private "
46 "(usr/local/include) header directory");
49 Library &Lib = getOrCreateLibrary(Directory, Libraries);
50 Lib.IsUnwrappedDylib =
true;
62 return Error::success();
66 while (Path.back() ==
'/')
67 Path = Path.slice(0, Path.size() - 1);
69 return llvm::StringSwitch<bool>(llvm::sys::path::extension(Path))
70 .Case(
".framework",
true)
75DirectoryScanner::getOrCreateLibrary(StringRef Path,
76 std::vector<Library> &Libs)
const {
77 if (Path.consume_front(RootPath) && Path.empty())
81 find_if(Libs, [Path](
const Library &L) {
return L.getPath() == Path; });
82 if (LibIt != Libs.end())
85 Libs.emplace_back(Path);
89Error DirectoryScanner::scanHeaders(StringRef Path,
Library &Lib,
91 StringRef ParentPath)
const {
93 auto &FS = FM.getVirtualFileSystem();
95 for (vfs::directory_iterator i = FS.dir_begin(Path, ec), ie; i != ie;
97 StringRef HeaderPath = i->path();
99 return createStringError(ec,
"unable to read: " + HeaderPath);
101 if (sys::fs::is_symlink_file(HeaderPath))
105 const StringRef Filename = sys::path::filename(HeaderPath);
106 if (Filename.starts_with(
"."))
110 if (FM.getOptionalDirectoryRef(HeaderPath))
111 SubDirectories.push_back(HeaderPath.str());
117 if (FS.status(HeaderPath) == std::errc::no_such_file_or_directory)
121 Lib.addHeaderFile(HeaderPath,
Type,
122 IncludeName.has_value() ? IncludeName.value() :
"");
128 llvm::sort(SubDirectories);
129 if (ParentPath.empty())
131 for (
const StringRef Dir : SubDirectories)
132 if (
Error Err = scanHeaders(Dir, Lib,
Type, BasePath, ParentPath))
135 return Error::success();
139DirectoryScanner::scanMultipleFrameworks(StringRef Directory,
140 std::vector<Library> &Libs)
const {
142 auto &FS = FM.getVirtualFileSystem();
143 for (vfs::directory_iterator i = FS.dir_begin(Directory, ec), ie; i != ie;
145 StringRef Curr = i->path();
148 if (ec == std::errc::no_such_file_or_directory) {
153 return createStringError(ec, Curr);
155 if (sys::fs::is_symlink_file(Curr))
159 if (!FM.getOptionalDirectoryRef(Curr))
161 Library &Framework = getOrCreateLibrary(Curr, Libs);
162 if (
Error Err = scanFrameworkDirectory(Curr, Framework))
167 return Error::success();
171DirectoryScanner::scanSubFrameworksDirectory(StringRef Directory,
172 std::vector<Library> &Libs)
const {
173 if (FM.getOptionalDirectoryRef(Directory))
174 return scanMultipleFrameworks(Directory, Libs);
176 std::error_code ec = std::make_error_code(std::errc::not_a_directory);
177 return createStringError(ec, Directory);
183DirectoryScanner::scanFrameworkVersionsDirectory(StringRef Path,
186 auto &FS = FM.getVirtualFileSystem();
187 for (vfs::directory_iterator i = FS.dir_begin(Path, ec), ie; i != ie;
189 const StringRef Curr = i->path();
192 if (ec == std::errc::no_such_file_or_directory) {
197 return createStringError(ec, Curr);
199 if (sys::fs::is_symlink_file(Curr))
203 if (!FM.getOptionalDirectoryRef(Curr))
207 getOrCreateLibrary(Curr, Lib.FrameworkVersions);
208 if (
Error Err = scanFrameworkDirectory(Curr, VersionedFramework))
212 return Error::success();
215llvm::Error DirectoryScanner::scanFrameworkDirectory(StringRef Path,
219 Framework.IsUnwrappedDylib =
220 Path.contains(
"Kernel.framework") || Path.contains(
"IOKit.framework");
226 auto &FS = FM.getVirtualFileSystem();
228 for (vfs::directory_iterator i = FS.dir_begin(Path, ec), ie; i != ie;
230 StringRef Curr = i->path();
232 if (ec == std::errc::no_such_file_or_directory) {
238 return createStringError(ec, Curr);
240 if (sys::fs::is_symlink_file(Curr))
243 StringRef
FileName = sys::path::filename(Curr);
251 if (
FileName.contains(
"PrivateHeaders")) {
257 if (
FileName.contains(
"Frameworks")) {
258 if (
Error Err = scanSubFrameworksDirectory(Curr, Framework.SubFrameworks))
263 if (
FileName.contains(
"Versions")) {
264 if (
Error Err = scanFrameworkVersionsDirectory(Curr, Framework))
270 return Error::success();
273llvm::Error DirectoryScanner::scanForFrameworks(StringRef Directory) {
278 static const char *SubDirectories[] = {
"System/Library/Frameworks/",
279 "System/Library/PrivateFrameworks/",
280 "System/Library/SubFrameworks"};
284 Library &Framework = getOrCreateLibrary(Directory, Libraries);
285 if (
Error Err = scanFrameworkDirectory(Directory, Framework))
287 return Error::success();
291 for (
const auto *SubDir : SubDirectories) {
292 SmallString<PATH_MAX> Path(Directory);
293 sys::path::append(Path, SubDir);
295 if (
Error Err = scanMultipleFrameworks(Path, Libraries))
299 return Error::success();
llvm::MachO::PathSeq PathSeq
OptionalDirectoryEntryRef getOptionalDirectoryRef(StringRef DirName, bool CacheFailure=true)
Get a DirectoryEntryRef if it exists, without doing anything on error.
llvm::Error scan(StringRef Directory)
Scan for all input files throughout directory.
static HeaderSeq getHeaders(ArrayRef< Library > Libraries)
Get all the header files in libraries.
The DirectoryScanner for collecting library files on the file system.
@ ScanFrameworks
Scanning Framework directory.
@ Public
Represents declarations accessible to all clients.
@ Private
Represents declarations accessible to a disclosed set of clients.
static bool isFramework(StringRef Path)
std::optional< std::string > createIncludeHeaderName(const StringRef FullPath)
Assemble expected way header will be included by clients.
bool isHeaderFile(StringRef Path)
Determine if Path is a header file.
std::vector< HeaderFile > HeaderSeq
@ Type
The name was classified as a type.
CustomizableOptional< DirectoryEntryRef > OptionalDirectoryEntryRef
Diagnostic wrappers for TextAPI types for error reporting.