1*0fca6ea1SDimitry Andric //===- HeaderFile.cpp ------------------------------------------*- C++ -*-===// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric 9*0fca6ea1SDimitry Andric #include "clang/InstallAPI/HeaderFile.h" 10*0fca6ea1SDimitry Andric #include "llvm/TextAPI/Utils.h" 11*0fca6ea1SDimitry Andric 12*0fca6ea1SDimitry Andric using namespace llvm; 13*0fca6ea1SDimitry Andric namespace clang::installapi { 14*0fca6ea1SDimitry Andric 15*0fca6ea1SDimitry Andric llvm::Regex HeaderFile::getFrameworkIncludeRule() { 16*0fca6ea1SDimitry Andric return llvm::Regex("/(.+)\\.framework/(.+)?Headers/(.+)"); 17*0fca6ea1SDimitry Andric } 18*0fca6ea1SDimitry Andric 19*0fca6ea1SDimitry Andric std::optional<std::string> createIncludeHeaderName(const StringRef FullPath) { 20*0fca6ea1SDimitry Andric // Headers in usr(/local)*/include. 21*0fca6ea1SDimitry Andric std::string Pattern = "/include/"; 22*0fca6ea1SDimitry Andric auto PathPrefix = FullPath.find(Pattern); 23*0fca6ea1SDimitry Andric if (PathPrefix != StringRef::npos) { 24*0fca6ea1SDimitry Andric PathPrefix += Pattern.size(); 25*0fca6ea1SDimitry Andric return FullPath.drop_front(PathPrefix).str(); 26*0fca6ea1SDimitry Andric } 27*0fca6ea1SDimitry Andric 28*0fca6ea1SDimitry Andric // Framework Headers. 29*0fca6ea1SDimitry Andric SmallVector<StringRef, 4> Matches; 30*0fca6ea1SDimitry Andric HeaderFile::getFrameworkIncludeRule().match(FullPath, &Matches); 31*0fca6ea1SDimitry Andric // Returned matches are always in stable order. 32*0fca6ea1SDimitry Andric if (Matches.size() != 4) 33*0fca6ea1SDimitry Andric return std::nullopt; 34*0fca6ea1SDimitry Andric 35*0fca6ea1SDimitry Andric return Matches[1].drop_front(Matches[1].rfind('/') + 1).str() + "/" + 36*0fca6ea1SDimitry Andric Matches[3].str(); 37*0fca6ea1SDimitry Andric } 38*0fca6ea1SDimitry Andric 39*0fca6ea1SDimitry Andric bool isHeaderFile(StringRef Path) { 40*0fca6ea1SDimitry Andric return StringSwitch<bool>(sys::path::extension(Path)) 41*0fca6ea1SDimitry Andric .Cases(".h", ".H", ".hh", ".hpp", ".hxx", true) 42*0fca6ea1SDimitry Andric .Default(false); 43*0fca6ea1SDimitry Andric } 44*0fca6ea1SDimitry Andric 45*0fca6ea1SDimitry Andric llvm::Expected<PathSeq> enumerateFiles(FileManager &FM, StringRef Directory) { 46*0fca6ea1SDimitry Andric PathSeq Files; 47*0fca6ea1SDimitry Andric std::error_code EC; 48*0fca6ea1SDimitry Andric auto &FS = FM.getVirtualFileSystem(); 49*0fca6ea1SDimitry Andric for (llvm::vfs::recursive_directory_iterator i(FS, Directory, EC), ie; 50*0fca6ea1SDimitry Andric i != ie; i.increment(EC)) { 51*0fca6ea1SDimitry Andric if (EC) 52*0fca6ea1SDimitry Andric return errorCodeToError(EC); 53*0fca6ea1SDimitry Andric 54*0fca6ea1SDimitry Andric // Skip files that do not exist. This usually happens for broken symlinks. 55*0fca6ea1SDimitry Andric if (FS.status(i->path()) == std::errc::no_such_file_or_directory) 56*0fca6ea1SDimitry Andric continue; 57*0fca6ea1SDimitry Andric 58*0fca6ea1SDimitry Andric StringRef Path = i->path(); 59*0fca6ea1SDimitry Andric if (isHeaderFile(Path)) 60*0fca6ea1SDimitry Andric Files.emplace_back(Path); 61*0fca6ea1SDimitry Andric } 62*0fca6ea1SDimitry Andric 63*0fca6ea1SDimitry Andric return Files; 64*0fca6ea1SDimitry Andric } 65*0fca6ea1SDimitry Andric 66*0fca6ea1SDimitry Andric HeaderGlob::HeaderGlob(StringRef GlobString, Regex &&Rule, HeaderType Type) 67*0fca6ea1SDimitry Andric : GlobString(GlobString), Rule(std::move(Rule)), Type(Type) {} 68*0fca6ea1SDimitry Andric 69*0fca6ea1SDimitry Andric bool HeaderGlob::match(const HeaderFile &Header) { 70*0fca6ea1SDimitry Andric if (Header.getType() != Type) 71*0fca6ea1SDimitry Andric return false; 72*0fca6ea1SDimitry Andric 73*0fca6ea1SDimitry Andric bool Match = Rule.match(Header.getPath()); 74*0fca6ea1SDimitry Andric if (Match) 75*0fca6ea1SDimitry Andric FoundMatch = true; 76*0fca6ea1SDimitry Andric return Match; 77*0fca6ea1SDimitry Andric } 78*0fca6ea1SDimitry Andric 79*0fca6ea1SDimitry Andric Expected<std::unique_ptr<HeaderGlob>> HeaderGlob::create(StringRef GlobString, 80*0fca6ea1SDimitry Andric HeaderType Type) { 81*0fca6ea1SDimitry Andric auto Rule = MachO::createRegexFromGlob(GlobString); 82*0fca6ea1SDimitry Andric if (!Rule) 83*0fca6ea1SDimitry Andric return Rule.takeError(); 84*0fca6ea1SDimitry Andric 85*0fca6ea1SDimitry Andric return std::make_unique<HeaderGlob>(GlobString, std::move(*Rule), Type); 86*0fca6ea1SDimitry Andric } 87*0fca6ea1SDimitry Andric 88*0fca6ea1SDimitry Andric } // namespace clang::installapi 89