1 //===- InstallAPI/HeaderFile.h ----------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// Representations of a library's headers for InstallAPI.
10 ///
11 //===----------------------------------------------------------------------===//
12
13 #ifndef LLVM_CLANG_INSTALLAPI_HEADERFILE_H
14 #define LLVM_CLANG_INSTALLAPI_HEADERFILE_H
15
16 #include "clang/Basic/FileManager.h"
17 #include "clang/Basic/LangStandard.h"
18 #include "clang/InstallAPI/MachO.h"
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/Support/ErrorHandling.h"
21 #include "llvm/Support/Regex.h"
22 #include <optional>
23 #include <string>
24
25 namespace clang::installapi {
26 enum class HeaderType {
27 /// Represents declarations accessible to all clients.
28 Public,
29 /// Represents declarations accessible to a disclosed set of clients.
30 Private,
31 /// Represents declarations only accessible as implementation details to the
32 /// input library.
33 Project,
34 /// Unset or unknown type.
35 Unknown,
36 };
37
getName(const HeaderType T)38 inline StringRef getName(const HeaderType T) {
39 switch (T) {
40 case HeaderType::Public:
41 return "Public";
42 case HeaderType::Private:
43 return "Private";
44 case HeaderType::Project:
45 return "Project";
46 case HeaderType::Unknown:
47 return "Unknown";
48 }
49 llvm_unreachable("unexpected header type");
50 }
51
52 class HeaderFile {
53 /// Full input path to header.
54 std::string FullPath;
55 /// Access level of header.
56 HeaderType Type;
57 /// Expected way header will be included by clients.
58 std::string IncludeName;
59 /// Supported language mode for header.
60 std::optional<clang::Language> Language;
61 /// Exclude header file from processing.
62 bool Excluded{false};
63 /// Add header file to processing.
64 bool Extra{false};
65 /// Specify that header file is the umbrella header for library.
66 bool Umbrella{false};
67
68 public:
69 HeaderFile() = delete;
70 HeaderFile(StringRef FullPath, HeaderType Type,
71 StringRef IncludeName = StringRef(),
72 std::optional<clang::Language> Language = std::nullopt)
FullPath(FullPath)73 : FullPath(FullPath), Type(Type), IncludeName(IncludeName),
74 Language(Language) {}
75
76 static llvm::Regex getFrameworkIncludeRule();
77
getType()78 HeaderType getType() const { return Type; }
getIncludeName()79 StringRef getIncludeName() const { return IncludeName; }
getPath()80 StringRef getPath() const { return FullPath; }
81
82 void setExtra(bool V = true) { Extra = V; }
83 void setExcluded(bool V = true) { Excluded = V; }
84 void setUmbrellaHeader(bool V = true) { Umbrella = V; }
isExtra()85 bool isExtra() const { return Extra; }
isExcluded()86 bool isExcluded() const { return Excluded; }
isUmbrellaHeader()87 bool isUmbrellaHeader() const { return Umbrella; }
88
useIncludeName()89 bool useIncludeName() const {
90 return Type != HeaderType::Project && !IncludeName.empty();
91 }
92
93 bool operator==(const HeaderFile &Other) const {
94 return std::tie(Type, FullPath, IncludeName, Language, Excluded, Extra,
95 Umbrella) == std::tie(Other.Type, Other.FullPath,
96 Other.IncludeName, Other.Language,
97 Other.Excluded, Other.Extra,
98 Other.Umbrella);
99 }
100
101 bool operator<(const HeaderFile &Other) const {
102 /// For parsing of headers based on ordering,
103 /// group by type, then whether its an umbrella.
104 /// Capture 'extra' headers last.
105 /// This optimizes the chance of a sucessful parse for
106 /// headers that violate IWYU.
107 if (isExtra() && Other.isExtra())
108 return std::tie(Type, Umbrella) < std::tie(Other.Type, Other.Umbrella);
109
110 return std::tie(Type, Umbrella, Extra, FullPath) <
111 std::tie(Other.Type, Other.Umbrella, Other.Extra, Other.FullPath);
112 }
113 };
114
115 /// Glob that represents a pattern of header files to retreive.
116 class HeaderGlob {
117 private:
118 std::string GlobString;
119 llvm::Regex Rule;
120 HeaderType Type;
121 bool FoundMatch{false};
122
123 public:
124 HeaderGlob(StringRef GlobString, llvm::Regex &&, HeaderType Type);
125
126 /// Create a header glob from string for the header access level.
127 static llvm::Expected<std::unique_ptr<HeaderGlob>>
128 create(StringRef GlobString, HeaderType Type);
129
130 /// Query if provided header matches glob.
131 bool match(const HeaderFile &Header);
132
133 /// Query if a header was matched in the glob, used primarily for error
134 /// reporting.
didMatch()135 bool didMatch() { return FoundMatch; }
136
137 /// Provide back input glob string.
str()138 StringRef str() { return GlobString; }
139 };
140
141 /// Assemble expected way header will be included by clients.
142 /// As in what maps inside the brackets of `#include <IncludeName.h>`
143 /// For example,
144 /// "/System/Library/Frameworks/Foo.framework/Headers/Foo.h" returns
145 /// "Foo/Foo.h"
146 ///
147 /// \param FullPath Path to the header file which includes the library
148 /// structure.
149 std::optional<std::string> createIncludeHeaderName(const StringRef FullPath);
150 using HeaderSeq = std::vector<HeaderFile>;
151
152 /// Determine if Path is a header file.
153 /// It does not touch the file system.
154 ///
155 /// \param Path File path to file.
156 bool isHeaderFile(StringRef Path);
157
158 /// Given input directory, collect all header files.
159 ///
160 /// \param FM FileManager for finding input files.
161 /// \param Directory Path to directory file.
162 llvm::Expected<PathSeq> enumerateFiles(clang::FileManager &FM,
163 StringRef Directory);
164
165 } // namespace clang::installapi
166
167 #endif // LLVM_CLANG_INSTALLAPI_HEADERFILE_H
168