xref: /freebsd-src/contrib/llvm-project/clang/lib/InstallAPI/HeaderFile.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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