brintos

brintos / llvm-project-archived public Read only

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