aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/InstallAPI/Frontend.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/InstallAPI/Frontend.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/InstallAPI/Frontend.cpp220
1 files changed, 220 insertions, 0 deletions
diff --git a/contrib/llvm-project/clang/lib/InstallAPI/Frontend.cpp b/contrib/llvm-project/clang/lib/InstallAPI/Frontend.cpp
new file mode 100644
index 000000000000..04d06f46d265
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/InstallAPI/Frontend.cpp
@@ -0,0 +1,220 @@
+//===- Frontend.cpp ---------------------------------------------*- C++ -*-===//
+//
+// 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/Frontend.h"
+#include "clang/AST/Availability.h"
+#include "clang/InstallAPI/FrontendRecords.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace llvm;
+using namespace llvm::MachO;
+
+namespace clang::installapi {
+std::pair<GlobalRecord *, FrontendAttrs *> FrontendRecordsSlice::addGlobal(
+ StringRef Name, RecordLinkage Linkage, GlobalRecord::Kind GV,
+ const clang::AvailabilityInfo Avail, const Decl *D, const HeaderType Access,
+ SymbolFlags Flags, bool Inlined) {
+
+ GlobalRecord *GR =
+ llvm::MachO::RecordsSlice::addGlobal(Name, Linkage, GV, Flags, Inlined);
+ auto Result = FrontendRecords.insert(
+ {GR, FrontendAttrs{Avail, D, D->getLocation(), Access}});
+ return {GR, &(Result.first->second)};
+}
+
+std::pair<ObjCInterfaceRecord *, FrontendAttrs *>
+FrontendRecordsSlice::addObjCInterface(StringRef Name, RecordLinkage Linkage,
+ const clang::AvailabilityInfo Avail,
+ const Decl *D, HeaderType Access,
+ bool IsEHType) {
+ ObjCIFSymbolKind SymType =
+ ObjCIFSymbolKind::Class | ObjCIFSymbolKind::MetaClass;
+ if (IsEHType)
+ SymType |= ObjCIFSymbolKind::EHType;
+
+ ObjCInterfaceRecord *ObjCR =
+ llvm::MachO::RecordsSlice::addObjCInterface(Name, Linkage, SymType);
+ auto Result = FrontendRecords.insert(
+ {ObjCR, FrontendAttrs{Avail, D, D->getLocation(), Access}});
+ return {ObjCR, &(Result.first->second)};
+}
+
+std::pair<ObjCCategoryRecord *, FrontendAttrs *>
+FrontendRecordsSlice::addObjCCategory(StringRef ClassToExtend,
+ StringRef CategoryName,
+ const clang::AvailabilityInfo Avail,
+ const Decl *D, HeaderType Access) {
+ ObjCCategoryRecord *ObjCR =
+ llvm::MachO::RecordsSlice::addObjCCategory(ClassToExtend, CategoryName);
+ auto Result = FrontendRecords.insert(
+ {ObjCR, FrontendAttrs{Avail, D, D->getLocation(), Access}});
+ return {ObjCR, &(Result.first->second)};
+}
+
+std::pair<ObjCIVarRecord *, FrontendAttrs *> FrontendRecordsSlice::addObjCIVar(
+ ObjCContainerRecord *Container, StringRef IvarName, RecordLinkage Linkage,
+ const clang::AvailabilityInfo Avail, const Decl *D, HeaderType Access,
+ const clang::ObjCIvarDecl::AccessControl AC) {
+ // If the decl otherwise would have been exported, check their access control.
+ // Ivar's linkage is also determined by this.
+ if ((Linkage == RecordLinkage::Exported) &&
+ ((AC == ObjCIvarDecl::Private) || (AC == ObjCIvarDecl::Package)))
+ Linkage = RecordLinkage::Internal;
+ ObjCIVarRecord *ObjCR =
+ llvm::MachO::RecordsSlice::addObjCIVar(Container, IvarName, Linkage);
+ auto Result = FrontendRecords.insert(
+ {ObjCR, FrontendAttrs{Avail, D, D->getLocation(), Access}});
+
+ return {ObjCR, &(Result.first->second)};
+}
+
+std::optional<HeaderType>
+InstallAPIContext::findAndRecordFile(const FileEntry *FE,
+ const Preprocessor &PP) {
+ if (!FE)
+ return std::nullopt;
+
+ // Check if header has been looked up already and whether it is something
+ // installapi should use.
+ auto It = KnownFiles.find(FE);
+ if (It != KnownFiles.end()) {
+ if (It->second != HeaderType::Unknown)
+ return It->second;
+ else
+ return std::nullopt;
+ }
+
+ // If file was not found, search by how the header was
+ // included. This is primarily to resolve headers found
+ // in a different location than what passed directly as input.
+ StringRef IncludeName = PP.getHeaderSearchInfo().getIncludeNameForHeader(FE);
+ auto BackupIt = KnownIncludes.find(IncludeName.str());
+ if (BackupIt != KnownIncludes.end()) {
+ KnownFiles[FE] = BackupIt->second;
+ return BackupIt->second;
+ }
+
+ // Record that the file was found to avoid future string searches for the
+ // same file.
+ KnownFiles.insert({FE, HeaderType::Unknown});
+ return std::nullopt;
+}
+
+void InstallAPIContext::addKnownHeader(const HeaderFile &H) {
+ auto FE = FM->getFile(H.getPath());
+ if (!FE)
+ return; // File does not exist.
+ KnownFiles[*FE] = H.getType();
+
+ if (!H.useIncludeName())
+ return;
+
+ KnownIncludes[H.getIncludeName()] = H.getType();
+}
+
+static StringRef getFileExtension(clang::Language Lang) {
+ switch (Lang) {
+ default:
+ llvm_unreachable("Unexpected language option.");
+ case clang::Language::C:
+ return ".c";
+ case clang::Language::CXX:
+ return ".cpp";
+ case clang::Language::ObjC:
+ return ".m";
+ case clang::Language::ObjCXX:
+ return ".mm";
+ }
+}
+
+std::unique_ptr<MemoryBuffer> createInputBuffer(InstallAPIContext &Ctx) {
+ assert(Ctx.Type != HeaderType::Unknown &&
+ "unexpected access level for parsing");
+ SmallString<4096> Contents;
+ raw_svector_ostream OS(Contents);
+ for (const HeaderFile &H : Ctx.InputHeaders) {
+ if (H.isExcluded())
+ continue;
+ if (H.getType() != Ctx.Type)
+ continue;
+ if (Ctx.LangMode == Language::C || Ctx.LangMode == Language::CXX)
+ OS << "#include ";
+ else
+ OS << "#import ";
+ if (H.useIncludeName())
+ OS << "<" << H.getIncludeName() << ">\n";
+ else
+ OS << "\"" << H.getPath() << "\"\n";
+
+ Ctx.addKnownHeader(H);
+ }
+ if (Contents.empty())
+ return nullptr;
+
+ SmallString<64> BufferName(
+ {"installapi-includes-", Ctx.Slice->getTriple().str(), "-",
+ getName(Ctx.Type), getFileExtension(Ctx.LangMode)});
+ return llvm::MemoryBuffer::getMemBufferCopy(Contents, BufferName);
+}
+
+std::string findLibrary(StringRef InstallName, FileManager &FM,
+ ArrayRef<std::string> FrameworkSearchPaths,
+ ArrayRef<std::string> LibrarySearchPaths,
+ ArrayRef<std::string> SearchPaths) {
+ auto getLibrary =
+ [&](const StringRef FullPath) -> std::optional<std::string> {
+ // Prefer TextAPI files when possible.
+ SmallString<PATH_MAX> TextAPIFilePath = FullPath;
+ replace_extension(TextAPIFilePath, ".tbd");
+
+ if (FM.getOptionalFileRef(TextAPIFilePath))
+ return std::string(TextAPIFilePath);
+
+ if (FM.getOptionalFileRef(FullPath))
+ return std::string(FullPath);
+
+ return std::nullopt;
+ };
+
+ const StringRef Filename = sys::path::filename(InstallName);
+ const bool IsFramework = sys::path::parent_path(InstallName)
+ .ends_with((Filename + ".framework").str());
+ if (IsFramework) {
+ for (const StringRef Path : FrameworkSearchPaths) {
+ SmallString<PATH_MAX> FullPath(Path);
+ sys::path::append(FullPath, Filename + StringRef(".framework"), Filename);
+ if (auto LibOrNull = getLibrary(FullPath))
+ return *LibOrNull;
+ }
+ } else {
+ // Copy Apple's linker behavior: If this is a .dylib inside a framework, do
+ // not search -L paths.
+ bool IsEmbeddedDylib = (sys::path::extension(InstallName) == ".dylib") &&
+ InstallName.contains(".framework/");
+ if (!IsEmbeddedDylib) {
+ for (const StringRef Path : LibrarySearchPaths) {
+ SmallString<PATH_MAX> FullPath(Path);
+ sys::path::append(FullPath, Filename);
+ if (auto LibOrNull = getLibrary(FullPath))
+ return *LibOrNull;
+ }
+ }
+ }
+
+ for (const StringRef Path : SearchPaths) {
+ SmallString<PATH_MAX> FullPath(Path);
+ sys::path::append(FullPath, InstallName);
+ if (auto LibOrNull = getLibrary(FullPath))
+ return *LibOrNull;
+ }
+
+ return {};
+}
+
+} // namespace clang::installapi