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