
* This patch introduces a container class, for holding records and attributes only collectible from the clang frontend, which is a subclass of `llvm::MachO::RecordsSlice` * This also prunes out collecting declarations from headers that aren't considered input to installapi. * Uses these constructs for collecting global objective-c interfaces.
130 lines
4.0 KiB
C++
130 lines
4.0 KiB
C++
//===- 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 "llvm/ADT/SmallString.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::MachO;
|
|
|
|
namespace clang::installapi {
|
|
|
|
GlobalRecord *FrontendRecordsSlice::addGlobal(
|
|
StringRef Name, RecordLinkage Linkage, GlobalRecord::Kind GV,
|
|
const clang::AvailabilityInfo Avail, const Decl *D, const HeaderType Access,
|
|
SymbolFlags Flags) {
|
|
|
|
auto *GR = llvm::MachO::RecordsSlice::addGlobal(Name, Linkage, GV, Flags);
|
|
FrontendRecords.insert({GR, FrontendAttrs{Avail, D, Access}});
|
|
return GR;
|
|
}
|
|
|
|
ObjCInterfaceRecord *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;
|
|
auto *ObjCR =
|
|
llvm::MachO::RecordsSlice::addObjCInterface(Name, Linkage, SymType);
|
|
FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}});
|
|
return ObjCR;
|
|
}
|
|
|
|
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.getType() != Ctx.Type)
|
|
continue;
|
|
if (Ctx.LangMode == Language::C || Ctx.LangMode == Language::CXX)
|
|
OS << "#include ";
|
|
else
|
|
OS << "#import ";
|
|
if (H.useIncludeName())
|
|
OS << "<" << H.getIncludeName() << ">";
|
|
else
|
|
OS << "\"" << H.getPath() << "\"";
|
|
|
|
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);
|
|
}
|
|
|
|
} // namespace clang::installapi
|