================ @@ -0,0 +1,300 @@ +//===- DirectoryScanner.cpp -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/InstallAPI/DirectoryScanner.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/TextAPI/DylibReader.h" + +using namespace llvm; +using namespace llvm::MachO; + +namespace clang::installapi { + +HeaderSeq DirectoryScanner::getHeaders(ArrayRef<Library> Libraries) { + HeaderSeq Headers; + for (const Library &Lib : Libraries) + llvm::append_range(Headers, Lib.Headers); + return Headers; +} + +llvm::Error DirectoryScanner::scan(StringRef Directory) { + if (Mode == ScanMode::ScanFrameworks) + return scanForFrameworks(Directory); + + return scanForUnwrappedLibraries(Directory); +} + +llvm::Error DirectoryScanner::scanForUnwrappedLibraries(StringRef Directory) { + // Check some known sub-directory locations. + auto GetDirectory = [&](const char *Sub) -> OptionalDirectoryEntryRef { + SmallString<PATH_MAX> Path(Directory); + sys::path::append(Path, Sub); + return FM.getOptionalDirectoryRef(Path); + }; + + auto DirPublic = GetDirectory("usr/include"); + auto DirPrivate = GetDirectory("usr/local/include"); + if (!DirPublic && !DirPrivate) { + std::error_code ec = std::make_error_code(std::errc::not_a_directory); + return createStringError(ec, + "cannot find any public (usr/include) or private " + "(usr/local/include) header directory"); + } + + Library &Lib = getOrCreateLibrary(Directory, Libraries); + Lib.IsUnwrappedDylib = true; + + if (DirPublic) + if (Error Err = scanHeaders(DirPublic->getName(), Lib, HeaderType::Public, + Directory)) + return Err; + + if (DirPrivate) + if (Error Err = scanHeaders(DirPrivate->getName(), Lib, HeaderType::Private, + Directory)) + return Err; + + return Error::success(); +} + +static bool isFramework(StringRef Path) { + while (Path.back() == '/') + Path = Path.slice(0, Path.size() - 1); + + return llvm::StringSwitch<bool>(llvm::sys::path::extension(Path)) + .Case(".framework", true) + .Default(false); +} + +Library & +DirectoryScanner::getOrCreateLibrary(StringRef Path, + std::vector<Library> &Libs) const { + if (Path.consume_front(RootPath) && Path.empty()) + Path = "/"; + + auto LibIt = + find_if(Libs, [Path](const Library &L) { return L.getPath() == Path; }); + if (LibIt != Libs.end()) + return *LibIt; + + Libs.emplace_back(Path); + return Libs.back(); +} + +Error DirectoryScanner::scanHeaders(StringRef Path, Library &Lib, + HeaderType Type, StringRef BasePath, + StringRef ParentPath) const { + std::error_code ec; + auto &FS = FM.getVirtualFileSystem(); + PathSeq SubDirectories; + for (vfs::directory_iterator i = FS.dir_begin(Path, ec), ie; i != ie; + i.increment(ec)) { + StringRef HeaderPath = i->path(); + if (ec) + return createStringError(ec, "unable to read: " + HeaderPath); + + if (sys::fs::is_symlink_file(HeaderPath)) + continue; + + // Ignore tmp files from unifdef. + const StringRef Filename = sys::path::filename(HeaderPath); + if (Filename.starts_with(".")) + continue; + + // If it is a directory, remember the subdirectory. + if (FM.getOptionalDirectoryRef(HeaderPath)) + SubDirectories.push_back(HeaderPath.str()); + + if (!isHeaderFile(HeaderPath)) + continue; + + // Skip files that do not exist. This usually happens for broken symlinks. + if (FS.status(HeaderPath) == std::errc::no_such_file_or_directory) + continue; + + auto IncludeName = createIncludeHeaderName(HeaderPath); + Lib.addHeaderFile(HeaderPath, Type, + IncludeName.has_value() ? IncludeName.value() : ""); + } + + // Go through the subdirectories. + // Sort the sub-directory first since different file systems might have + // different traverse order. + llvm::sort(SubDirectories); + if (ParentPath.empty()) + ParentPath = Path; + for (const StringRef Dir : SubDirectories) + return scanHeaders(Dir, Lib, Type, BasePath, ParentPath); ---------------- mikerice1969 wrote:
Hi @cyndyishida Our static verification run reports that this loop always exits on the first iteration (so it is not really a loop). Is that really what you want here? If you only want to scan the first item maybe something other than a loop makes sense? https://github.com/llvm/llvm-project/pull/94508 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits