Path: blob/main/contrib/llvm-project/clang/lib/InstallAPI/Frontend.cpp
35232 views
//===- Frontend.cpp ---------------------------------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "clang/InstallAPI/Frontend.h"9#include "clang/AST/Availability.h"10#include "clang/InstallAPI/FrontendRecords.h"11#include "llvm/ADT/SmallString.h"12#include "llvm/ADT/StringRef.h"1314using namespace llvm;15using namespace llvm::MachO;1617namespace clang::installapi {18std::pair<GlobalRecord *, FrontendAttrs *> FrontendRecordsSlice::addGlobal(19StringRef Name, RecordLinkage Linkage, GlobalRecord::Kind GV,20const clang::AvailabilityInfo Avail, const Decl *D, const HeaderType Access,21SymbolFlags Flags, bool Inlined) {2223GlobalRecord *GR =24llvm::MachO::RecordsSlice::addGlobal(Name, Linkage, GV, Flags, Inlined);25auto Result = FrontendRecords.insert(26{GR, FrontendAttrs{Avail, D, D->getLocation(), Access}});27return {GR, &(Result.first->second)};28}2930std::pair<ObjCInterfaceRecord *, FrontendAttrs *>31FrontendRecordsSlice::addObjCInterface(StringRef Name, RecordLinkage Linkage,32const clang::AvailabilityInfo Avail,33const Decl *D, HeaderType Access,34bool IsEHType) {35ObjCIFSymbolKind SymType =36ObjCIFSymbolKind::Class | ObjCIFSymbolKind::MetaClass;37if (IsEHType)38SymType |= ObjCIFSymbolKind::EHType;3940ObjCInterfaceRecord *ObjCR =41llvm::MachO::RecordsSlice::addObjCInterface(Name, Linkage, SymType);42auto Result = FrontendRecords.insert(43{ObjCR, FrontendAttrs{Avail, D, D->getLocation(), Access}});44return {ObjCR, &(Result.first->second)};45}4647std::pair<ObjCCategoryRecord *, FrontendAttrs *>48FrontendRecordsSlice::addObjCCategory(StringRef ClassToExtend,49StringRef CategoryName,50const clang::AvailabilityInfo Avail,51const Decl *D, HeaderType Access) {52ObjCCategoryRecord *ObjCR =53llvm::MachO::RecordsSlice::addObjCCategory(ClassToExtend, CategoryName);54auto Result = FrontendRecords.insert(55{ObjCR, FrontendAttrs{Avail, D, D->getLocation(), Access}});56return {ObjCR, &(Result.first->second)};57}5859std::pair<ObjCIVarRecord *, FrontendAttrs *> FrontendRecordsSlice::addObjCIVar(60ObjCContainerRecord *Container, StringRef IvarName, RecordLinkage Linkage,61const clang::AvailabilityInfo Avail, const Decl *D, HeaderType Access,62const clang::ObjCIvarDecl::AccessControl AC) {63// If the decl otherwise would have been exported, check their access control.64// Ivar's linkage is also determined by this.65if ((Linkage == RecordLinkage::Exported) &&66((AC == ObjCIvarDecl::Private) || (AC == ObjCIvarDecl::Package)))67Linkage = RecordLinkage::Internal;68ObjCIVarRecord *ObjCR =69llvm::MachO::RecordsSlice::addObjCIVar(Container, IvarName, Linkage);70auto Result = FrontendRecords.insert(71{ObjCR, FrontendAttrs{Avail, D, D->getLocation(), Access}});7273return {ObjCR, &(Result.first->second)};74}7576std::optional<HeaderType>77InstallAPIContext::findAndRecordFile(const FileEntry *FE,78const Preprocessor &PP) {79if (!FE)80return std::nullopt;8182// Check if header has been looked up already and whether it is something83// installapi should use.84auto It = KnownFiles.find(FE);85if (It != KnownFiles.end()) {86if (It->second != HeaderType::Unknown)87return It->second;88else89return std::nullopt;90}9192// If file was not found, search by how the header was93// included. This is primarily to resolve headers found94// in a different location than what passed directly as input.95StringRef IncludeName = PP.getHeaderSearchInfo().getIncludeNameForHeader(FE);96auto BackupIt = KnownIncludes.find(IncludeName.str());97if (BackupIt != KnownIncludes.end()) {98KnownFiles[FE] = BackupIt->second;99return BackupIt->second;100}101102// Record that the file was found to avoid future string searches for the103// same file.104KnownFiles.insert({FE, HeaderType::Unknown});105return std::nullopt;106}107108void InstallAPIContext::addKnownHeader(const HeaderFile &H) {109auto FE = FM->getFile(H.getPath());110if (!FE)111return; // File does not exist.112KnownFiles[*FE] = H.getType();113114if (!H.useIncludeName())115return;116117KnownIncludes[H.getIncludeName()] = H.getType();118}119120static StringRef getFileExtension(clang::Language Lang) {121switch (Lang) {122default:123llvm_unreachable("Unexpected language option.");124case clang::Language::C:125return ".c";126case clang::Language::CXX:127return ".cpp";128case clang::Language::ObjC:129return ".m";130case clang::Language::ObjCXX:131return ".mm";132}133}134135std::unique_ptr<MemoryBuffer> createInputBuffer(InstallAPIContext &Ctx) {136assert(Ctx.Type != HeaderType::Unknown &&137"unexpected access level for parsing");138SmallString<4096> Contents;139raw_svector_ostream OS(Contents);140for (const HeaderFile &H : Ctx.InputHeaders) {141if (H.isExcluded())142continue;143if (H.getType() != Ctx.Type)144continue;145if (Ctx.LangMode == Language::C || Ctx.LangMode == Language::CXX)146OS << "#include ";147else148OS << "#import ";149if (H.useIncludeName())150OS << "<" << H.getIncludeName() << ">\n";151else152OS << "\"" << H.getPath() << "\"\n";153154Ctx.addKnownHeader(H);155}156if (Contents.empty())157return nullptr;158159SmallString<64> BufferName(160{"installapi-includes-", Ctx.Slice->getTriple().str(), "-",161getName(Ctx.Type), getFileExtension(Ctx.LangMode)});162return llvm::MemoryBuffer::getMemBufferCopy(Contents, BufferName);163}164165std::string findLibrary(StringRef InstallName, FileManager &FM,166ArrayRef<std::string> FrameworkSearchPaths,167ArrayRef<std::string> LibrarySearchPaths,168ArrayRef<std::string> SearchPaths) {169auto getLibrary =170[&](const StringRef FullPath) -> std::optional<std::string> {171// Prefer TextAPI files when possible.172SmallString<PATH_MAX> TextAPIFilePath = FullPath;173replace_extension(TextAPIFilePath, ".tbd");174175if (FM.getOptionalFileRef(TextAPIFilePath))176return std::string(TextAPIFilePath);177178if (FM.getOptionalFileRef(FullPath))179return std::string(FullPath);180181return std::nullopt;182};183184const StringRef Filename = sys::path::filename(InstallName);185const bool IsFramework = sys::path::parent_path(InstallName)186.ends_with((Filename + ".framework").str());187if (IsFramework) {188for (const StringRef Path : FrameworkSearchPaths) {189SmallString<PATH_MAX> FullPath(Path);190sys::path::append(FullPath, Filename + StringRef(".framework"), Filename);191if (auto LibOrNull = getLibrary(FullPath))192return *LibOrNull;193}194} else {195// Copy Apple's linker behavior: If this is a .dylib inside a framework, do196// not search -L paths.197bool IsEmbeddedDylib = (sys::path::extension(InstallName) == ".dylib") &&198InstallName.contains(".framework/");199if (!IsEmbeddedDylib) {200for (const StringRef Path : LibrarySearchPaths) {201SmallString<PATH_MAX> FullPath(Path);202sys::path::append(FullPath, Filename);203if (auto LibOrNull = getLibrary(FullPath))204return *LibOrNull;205}206}207}208209for (const StringRef Path : SearchPaths) {210SmallString<PATH_MAX> FullPath(Path);211sys::path::append(FullPath, InstallName);212if (auto LibOrNull = getLibrary(FullPath))213return *LibOrNull;214}215216return {};217}218219} // namespace clang::installapi220221222