10#include "llvm/ADT/StringRef.h"
11#include "llvm/ADT/StringSwitch.h"
12#include "llvm/TextAPI/DylibReader.h"
21 for (
const Library &Lib : Libraries)
22 llvm::append_range(Headers, Lib.Headers);
28 return scanForFrameworks(Directory);
30 return scanForUnwrappedLibraries(Directory);
33llvm::Error DirectoryScanner::scanForUnwrappedLibraries(StringRef Directory) {
37 sys::path::append(
Path, Sub);
41 auto DirPublic = GetDirectory(
"usr/include");
42 auto DirPrivate = GetDirectory(
"usr/local/include");
43 if (!DirPublic && !DirPrivate) {
44 std::error_code ec = std::make_error_code(std::errc::not_a_directory);
45 return createStringError(ec,
46 "cannot find any public (usr/include) or private "
47 "(usr/local/include) header directory");
50 Library &Lib = getOrCreateLibrary(Directory, Libraries);
51 Lib.IsUnwrappedDylib =
true;
63 return Error::success();
67 while (
Path.back() ==
'/')
70 return llvm::StringSwitch<bool>(llvm::sys::path::extension(
Path))
71 .Case(
".framework",
true)
76DirectoryScanner::getOrCreateLibrary(StringRef
Path,
77 std::vector<Library> &Libs)
const {
78 if (
Path.consume_front(RootPath) &&
Path.empty())
82 find_if(Libs, [
Path](
const Library &L) {
return L.getPath() ==
Path; });
83 if (LibIt != Libs.end())
86 Libs.emplace_back(
Path);
90Error DirectoryScanner::scanHeaders(StringRef
Path, Library &Lib,
92 StringRef ParentPath)
const {
96 for (vfs::directory_iterator i = FS.dir_begin(
Path, ec), ie; i != ie;
98 StringRef HeaderPath = i->path();
100 return createStringError(ec,
"unable to read: " + HeaderPath);
102 if (sys::fs::is_symlink_file(HeaderPath))
106 const StringRef
Filename = sys::path::filename(HeaderPath);
112 SubDirectories.push_back(HeaderPath.str());
118 if (FS.status(HeaderPath) == std::errc::no_such_file_or_directory)
122 Lib.addHeaderFile(HeaderPath, Type,
123 IncludeName.has_value() ? IncludeName.value() :
"");
129 llvm::sort(SubDirectories);
130 if (ParentPath.empty())
132 for (
const StringRef Dir : SubDirectories)
133 if (Error Err = scanHeaders(Dir, Lib, Type, BasePath, ParentPath))
136 return Error::success();
140DirectoryScanner::scanMultipleFrameworks(StringRef Directory,
141 std::vector<Library> &Libs)
const {
144 for (vfs::directory_iterator i = FS.dir_begin(Directory, ec), ie; i != ie;
146 StringRef Curr = i->path();
149 if (ec == std::errc::no_such_file_or_directory) {
154 return createStringError(ec, Curr);
156 if (sys::fs::is_symlink_file(Curr))
162 Library &Framework = getOrCreateLibrary(Curr, Libs);
163 if (Error Err = scanFrameworkDirectory(Curr, Framework))
168 return Error::success();
172DirectoryScanner::scanSubFrameworksDirectory(StringRef Directory,
173 std::vector<Library> &Libs)
const {
175 return scanMultipleFrameworks(Directory, Libs);
177 std::error_code ec = std::make_error_code(std::errc::not_a_directory);
178 return createStringError(ec, Directory);
184DirectoryScanner::scanFrameworkVersionsDirectory(StringRef
Path,
185 Library &Lib)
const {
188 for (vfs::directory_iterator i = FS.dir_begin(
Path, ec), ie; i != ie;
190 const StringRef Curr = i->path();
193 if (ec == std::errc::no_such_file_or_directory) {
198 return createStringError(ec, Curr);
200 if (sys::fs::is_symlink_file(Curr))
208 getOrCreateLibrary(Curr, Lib.FrameworkVersions);
209 if (Error Err = scanFrameworkDirectory(Curr, VersionedFramework))
213 return Error::success();
216llvm::Error DirectoryScanner::scanFrameworkDirectory(StringRef
Path,
217 Library &Framework)
const {
220 Framework.IsUnwrappedDylib =
221 Path.contains(
"Kernel.framework") ||
Path.contains(
"IOKit.framework");
229 for (vfs::directory_iterator i = FS.dir_begin(
Path, ec), ie; i != ie;
231 StringRef Curr = i->path();
233 if (ec == std::errc::no_such_file_or_directory) {
239 return createStringError(ec, Curr);
241 if (sys::fs::is_symlink_file(Curr))
244 StringRef
FileName = sys::path::filename(Curr);
252 if (
FileName.contains(
"PrivateHeaders")) {
258 if (
FileName.contains(
"Frameworks")) {
259 if (Error Err = scanSubFrameworksDirectory(Curr, Framework.SubFrameworks))
264 if (
FileName.contains(
"Versions")) {
265 if (Error Err = scanFrameworkVersionsDirectory(Curr, Framework))
271 return Error::success();
274llvm::Error DirectoryScanner::scanForFrameworks(StringRef Directory) {
279 static const char *SubDirectories[] = {
"System/Library/Frameworks/",
280 "System/Library/PrivateFrameworks/"};
284 Library &Framework = getOrCreateLibrary(Directory, Libraries);
285 if (Error Err = scanFrameworkDirectory(Directory, Framework))
287 return Error::success();
291 for (
const auto *SubDir : SubDirectories) {
293 sys::path::append(
Path, SubDir);
295 if (Error Err = scanMultipleFrameworks(
Path, Libraries))
299 return Error::success();
llvm::MachO::PathSeq PathSeq
llvm::vfs::FileSystem & getVirtualFileSystem() const
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.
std::vector< HeaderFile > HeaderSeq
@ 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.
Diagnostic wrappers for TextAPI types for error reporting.