Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/InstallAPI/Frontend.cpp
35232 views
1
//===- Frontend.cpp ---------------------------------------------*- 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
#include "clang/InstallAPI/Frontend.h"
10
#include "clang/AST/Availability.h"
11
#include "clang/InstallAPI/FrontendRecords.h"
12
#include "llvm/ADT/SmallString.h"
13
#include "llvm/ADT/StringRef.h"
14
15
using namespace llvm;
16
using namespace llvm::MachO;
17
18
namespace clang::installapi {
19
std::pair<GlobalRecord *, FrontendAttrs *> FrontendRecordsSlice::addGlobal(
20
StringRef Name, RecordLinkage Linkage, GlobalRecord::Kind GV,
21
const clang::AvailabilityInfo Avail, const Decl *D, const HeaderType Access,
22
SymbolFlags Flags, bool Inlined) {
23
24
GlobalRecord *GR =
25
llvm::MachO::RecordsSlice::addGlobal(Name, Linkage, GV, Flags, Inlined);
26
auto Result = FrontendRecords.insert(
27
{GR, FrontendAttrs{Avail, D, D->getLocation(), Access}});
28
return {GR, &(Result.first->second)};
29
}
30
31
std::pair<ObjCInterfaceRecord *, FrontendAttrs *>
32
FrontendRecordsSlice::addObjCInterface(StringRef Name, RecordLinkage Linkage,
33
const clang::AvailabilityInfo Avail,
34
const Decl *D, HeaderType Access,
35
bool IsEHType) {
36
ObjCIFSymbolKind SymType =
37
ObjCIFSymbolKind::Class | ObjCIFSymbolKind::MetaClass;
38
if (IsEHType)
39
SymType |= ObjCIFSymbolKind::EHType;
40
41
ObjCInterfaceRecord *ObjCR =
42
llvm::MachO::RecordsSlice::addObjCInterface(Name, Linkage, SymType);
43
auto Result = FrontendRecords.insert(
44
{ObjCR, FrontendAttrs{Avail, D, D->getLocation(), Access}});
45
return {ObjCR, &(Result.first->second)};
46
}
47
48
std::pair<ObjCCategoryRecord *, FrontendAttrs *>
49
FrontendRecordsSlice::addObjCCategory(StringRef ClassToExtend,
50
StringRef CategoryName,
51
const clang::AvailabilityInfo Avail,
52
const Decl *D, HeaderType Access) {
53
ObjCCategoryRecord *ObjCR =
54
llvm::MachO::RecordsSlice::addObjCCategory(ClassToExtend, CategoryName);
55
auto Result = FrontendRecords.insert(
56
{ObjCR, FrontendAttrs{Avail, D, D->getLocation(), Access}});
57
return {ObjCR, &(Result.first->second)};
58
}
59
60
std::pair<ObjCIVarRecord *, FrontendAttrs *> FrontendRecordsSlice::addObjCIVar(
61
ObjCContainerRecord *Container, StringRef IvarName, RecordLinkage Linkage,
62
const clang::AvailabilityInfo Avail, const Decl *D, HeaderType Access,
63
const clang::ObjCIvarDecl::AccessControl AC) {
64
// If the decl otherwise would have been exported, check their access control.
65
// Ivar's linkage is also determined by this.
66
if ((Linkage == RecordLinkage::Exported) &&
67
((AC == ObjCIvarDecl::Private) || (AC == ObjCIvarDecl::Package)))
68
Linkage = RecordLinkage::Internal;
69
ObjCIVarRecord *ObjCR =
70
llvm::MachO::RecordsSlice::addObjCIVar(Container, IvarName, Linkage);
71
auto Result = FrontendRecords.insert(
72
{ObjCR, FrontendAttrs{Avail, D, D->getLocation(), Access}});
73
74
return {ObjCR, &(Result.first->second)};
75
}
76
77
std::optional<HeaderType>
78
InstallAPIContext::findAndRecordFile(const FileEntry *FE,
79
const Preprocessor &PP) {
80
if (!FE)
81
return std::nullopt;
82
83
// Check if header has been looked up already and whether it is something
84
// installapi should use.
85
auto It = KnownFiles.find(FE);
86
if (It != KnownFiles.end()) {
87
if (It->second != HeaderType::Unknown)
88
return It->second;
89
else
90
return std::nullopt;
91
}
92
93
// If file was not found, search by how the header was
94
// included. This is primarily to resolve headers found
95
// in a different location than what passed directly as input.
96
StringRef IncludeName = PP.getHeaderSearchInfo().getIncludeNameForHeader(FE);
97
auto BackupIt = KnownIncludes.find(IncludeName.str());
98
if (BackupIt != KnownIncludes.end()) {
99
KnownFiles[FE] = BackupIt->second;
100
return BackupIt->second;
101
}
102
103
// Record that the file was found to avoid future string searches for the
104
// same file.
105
KnownFiles.insert({FE, HeaderType::Unknown});
106
return std::nullopt;
107
}
108
109
void InstallAPIContext::addKnownHeader(const HeaderFile &H) {
110
auto FE = FM->getFile(H.getPath());
111
if (!FE)
112
return; // File does not exist.
113
KnownFiles[*FE] = H.getType();
114
115
if (!H.useIncludeName())
116
return;
117
118
KnownIncludes[H.getIncludeName()] = H.getType();
119
}
120
121
static StringRef getFileExtension(clang::Language Lang) {
122
switch (Lang) {
123
default:
124
llvm_unreachable("Unexpected language option.");
125
case clang::Language::C:
126
return ".c";
127
case clang::Language::CXX:
128
return ".cpp";
129
case clang::Language::ObjC:
130
return ".m";
131
case clang::Language::ObjCXX:
132
return ".mm";
133
}
134
}
135
136
std::unique_ptr<MemoryBuffer> createInputBuffer(InstallAPIContext &Ctx) {
137
assert(Ctx.Type != HeaderType::Unknown &&
138
"unexpected access level for parsing");
139
SmallString<4096> Contents;
140
raw_svector_ostream OS(Contents);
141
for (const HeaderFile &H : Ctx.InputHeaders) {
142
if (H.isExcluded())
143
continue;
144
if (H.getType() != Ctx.Type)
145
continue;
146
if (Ctx.LangMode == Language::C || Ctx.LangMode == Language::CXX)
147
OS << "#include ";
148
else
149
OS << "#import ";
150
if (H.useIncludeName())
151
OS << "<" << H.getIncludeName() << ">\n";
152
else
153
OS << "\"" << H.getPath() << "\"\n";
154
155
Ctx.addKnownHeader(H);
156
}
157
if (Contents.empty())
158
return nullptr;
159
160
SmallString<64> BufferName(
161
{"installapi-includes-", Ctx.Slice->getTriple().str(), "-",
162
getName(Ctx.Type), getFileExtension(Ctx.LangMode)});
163
return llvm::MemoryBuffer::getMemBufferCopy(Contents, BufferName);
164
}
165
166
std::string findLibrary(StringRef InstallName, FileManager &FM,
167
ArrayRef<std::string> FrameworkSearchPaths,
168
ArrayRef<std::string> LibrarySearchPaths,
169
ArrayRef<std::string> SearchPaths) {
170
auto getLibrary =
171
[&](const StringRef FullPath) -> std::optional<std::string> {
172
// Prefer TextAPI files when possible.
173
SmallString<PATH_MAX> TextAPIFilePath = FullPath;
174
replace_extension(TextAPIFilePath, ".tbd");
175
176
if (FM.getOptionalFileRef(TextAPIFilePath))
177
return std::string(TextAPIFilePath);
178
179
if (FM.getOptionalFileRef(FullPath))
180
return std::string(FullPath);
181
182
return std::nullopt;
183
};
184
185
const StringRef Filename = sys::path::filename(InstallName);
186
const bool IsFramework = sys::path::parent_path(InstallName)
187
.ends_with((Filename + ".framework").str());
188
if (IsFramework) {
189
for (const StringRef Path : FrameworkSearchPaths) {
190
SmallString<PATH_MAX> FullPath(Path);
191
sys::path::append(FullPath, Filename + StringRef(".framework"), Filename);
192
if (auto LibOrNull = getLibrary(FullPath))
193
return *LibOrNull;
194
}
195
} else {
196
// Copy Apple's linker behavior: If this is a .dylib inside a framework, do
197
// not search -L paths.
198
bool IsEmbeddedDylib = (sys::path::extension(InstallName) == ".dylib") &&
199
InstallName.contains(".framework/");
200
if (!IsEmbeddedDylib) {
201
for (const StringRef Path : LibrarySearchPaths) {
202
SmallString<PATH_MAX> FullPath(Path);
203
sys::path::append(FullPath, Filename);
204
if (auto LibOrNull = getLibrary(FullPath))
205
return *LibOrNull;
206
}
207
}
208
}
209
210
for (const StringRef Path : SearchPaths) {
211
SmallString<PATH_MAX> FullPath(Path);
212
sys::path::append(FullPath, InstallName);
213
if (auto LibOrNull = getLibrary(FullPath))
214
return *LibOrNull;
215
}
216
217
return {};
218
}
219
220
} // namespace clang::installapi
221
222