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 "llvm/ADT/SmallString.h" 12 #include "llvm/ADT/StringRef.h" 13 14 using namespace llvm; 15 using namespace llvm::MachO; 16 17 namespace clang::installapi { 18 19 GlobalRecord *FrontendRecordsSlice::addGlobal( 20 StringRef Name, RecordLinkage Linkage, GlobalRecord::Kind GV, 21 const clang::AvailabilityInfo Avail, const Decl *D, const HeaderType Access, 22 SymbolFlags Flags) { 23 24 auto *GR = llvm::MachO::RecordsSlice::addGlobal(Name, Linkage, GV, Flags); 25 FrontendRecords.insert({GR, FrontendAttrs{Avail, D, Access}}); 26 return GR; 27 } 28 29 ObjCInterfaceRecord *FrontendRecordsSlice::addObjCInterface( 30 StringRef Name, RecordLinkage Linkage, const clang::AvailabilityInfo Avail, 31 const Decl *D, HeaderType Access, bool IsEHType) { 32 ObjCIFSymbolKind SymType = 33 ObjCIFSymbolKind::Class | ObjCIFSymbolKind::MetaClass; 34 if (IsEHType) 35 SymType |= ObjCIFSymbolKind::EHType; 36 auto *ObjCR = 37 llvm::MachO::RecordsSlice::addObjCInterface(Name, Linkage, SymType); 38 FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}}); 39 return ObjCR; 40 } 41 42 ObjCCategoryRecord *FrontendRecordsSlice::addObjCCategory( 43 StringRef ClassToExtend, StringRef CategoryName, 44 const clang::AvailabilityInfo Avail, const Decl *D, HeaderType Access) { 45 auto *ObjCR = 46 llvm::MachO::RecordsSlice::addObjCCategory(ClassToExtend, CategoryName); 47 FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}}); 48 return ObjCR; 49 } 50 51 ObjCIVarRecord *FrontendRecordsSlice::addObjCIVar( 52 ObjCContainerRecord *Container, StringRef IvarName, RecordLinkage Linkage, 53 const clang::AvailabilityInfo Avail, const Decl *D, HeaderType Access, 54 const clang::ObjCIvarDecl::AccessControl AC) { 55 // If the decl otherwise would have been exported, check their access control. 56 // Ivar's linkage is also determined by this. 57 if ((Linkage == RecordLinkage::Exported) && 58 ((AC == ObjCIvarDecl::Private) || (AC == ObjCIvarDecl::Package))) 59 Linkage = RecordLinkage::Internal; 60 auto *ObjCR = 61 llvm::MachO::RecordsSlice::addObjCIVar(Container, IvarName, Linkage); 62 FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}}); 63 64 return nullptr; 65 } 66 67 std::optional<HeaderType> 68 InstallAPIContext::findAndRecordFile(const FileEntry *FE, 69 const Preprocessor &PP) { 70 if (!FE) 71 return std::nullopt; 72 73 // Check if header has been looked up already and whether it is something 74 // installapi should use. 75 auto It = KnownFiles.find(FE); 76 if (It != KnownFiles.end()) { 77 if (It->second != HeaderType::Unknown) 78 return It->second; 79 else 80 return std::nullopt; 81 } 82 83 // If file was not found, search by how the header was 84 // included. This is primarily to resolve headers found 85 // in a different location than what passed directly as input. 86 StringRef IncludeName = PP.getHeaderSearchInfo().getIncludeNameForHeader(FE); 87 auto BackupIt = KnownIncludes.find(IncludeName.str()); 88 if (BackupIt != KnownIncludes.end()) { 89 KnownFiles[FE] = BackupIt->second; 90 return BackupIt->second; 91 } 92 93 // Record that the file was found to avoid future string searches for the 94 // same file. 95 KnownFiles.insert({FE, HeaderType::Unknown}); 96 return std::nullopt; 97 } 98 99 void InstallAPIContext::addKnownHeader(const HeaderFile &H) { 100 auto FE = FM->getFile(H.getPath()); 101 if (!FE) 102 return; // File does not exist. 103 KnownFiles[*FE] = H.getType(); 104 105 if (!H.useIncludeName()) 106 return; 107 108 KnownIncludes[H.getIncludeName()] = H.getType(); 109 } 110 111 static StringRef getFileExtension(clang::Language Lang) { 112 switch (Lang) { 113 default: 114 llvm_unreachable("Unexpected language option."); 115 case clang::Language::C: 116 return ".c"; 117 case clang::Language::CXX: 118 return ".cpp"; 119 case clang::Language::ObjC: 120 return ".m"; 121 case clang::Language::ObjCXX: 122 return ".mm"; 123 } 124 } 125 126 std::unique_ptr<MemoryBuffer> createInputBuffer(InstallAPIContext &Ctx) { 127 assert(Ctx.Type != HeaderType::Unknown && 128 "unexpected access level for parsing"); 129 SmallString<4096> Contents; 130 raw_svector_ostream OS(Contents); 131 for (const HeaderFile &H : Ctx.InputHeaders) { 132 if (H.getType() != Ctx.Type) 133 continue; 134 if (Ctx.LangMode == Language::C || Ctx.LangMode == Language::CXX) 135 OS << "#include "; 136 else 137 OS << "#import "; 138 if (H.useIncludeName()) 139 OS << "<" << H.getIncludeName() << ">"; 140 else 141 OS << "\"" << H.getPath() << "\""; 142 143 Ctx.addKnownHeader(H); 144 } 145 if (Contents.empty()) 146 return nullptr; 147 148 SmallString<64> BufferName( 149 {"installapi-includes-", Ctx.Slice->getTriple().str(), "-", 150 getName(Ctx.Type), getFileExtension(Ctx.LangMode)}); 151 return llvm::MemoryBuffer::getMemBufferCopy(Contents, BufferName); 152 } 153 154 } // namespace clang::installapi 155