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 "clang/InstallAPI/FrontendRecords.h" 12 #include "llvm/ADT/SmallString.h" 13 #include "llvm/ADT/StringRef.h" 14 15 using namespace llvm; 16 using namespace llvm::MachO; 17 18 namespace clang::installapi { 19 std::pair<GlobalRecord *, FrontendAttrs *> 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 GlobalRecord *GR = 25 llvm::MachO::RecordsSlice::addGlobal(Name, Linkage, GV, Flags, Inlined); 26 auto Result = FrontendRecords.insert({GR, FrontendAttrs{Avail, D, Access}}); 27 return {GR, &(Result.first->second)}; 28 } 29 30 std::pair<ObjCInterfaceRecord *, FrontendAttrs *> 31 FrontendRecordsSlice::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 = 43 FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}}); 44 return {ObjCR, &(Result.first->second)}; 45 } 46 47 std::pair<ObjCCategoryRecord *, FrontendAttrs *> 48 FrontendRecordsSlice::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 = 55 FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}}); 56 return {ObjCR, &(Result.first->second)}; 57 } 58 59 std::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 = 71 FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}}); 72 73 return {ObjCR, &(Result.first->second)}; 74 } 75 76 std::optional<HeaderType> 77 InstallAPIContext::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 something 83 // 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 else 89 return std::nullopt; 90 } 91 92 // If file was not found, search by how the header was 93 // included. This is primarily to resolve headers found 94 // in a different location than what passed directly as input. 95 StringRef IncludeName = PP.getHeaderSearchInfo().getIncludeNameForHeader(FE); 96 auto BackupIt = KnownIncludes.find(IncludeName.str()); 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 the 103 // same file. 104 KnownFiles.insert({FE, HeaderType::Unknown}); 105 return std::nullopt; 106 } 107 108 void InstallAPIContext::addKnownHeader(const HeaderFile &H) { 109 auto FE = FM->getFile(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 120 static 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 135 std::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.getType() != Ctx.Type) 142 continue; 143 if (Ctx.LangMode == Language::C || Ctx.LangMode == Language::CXX) 144 OS << "#include "; 145 else 146 OS << "#import "; 147 if (H.useIncludeName()) 148 OS << "<" << H.getIncludeName() << ">\n"; 149 else 150 OS << "\"" << H.getPath() << "\"\n"; 151 152 Ctx.addKnownHeader(H); 153 } 154 if (Contents.empty()) 155 return nullptr; 156 157 SmallString<64> BufferName( 158 {"installapi-includes-", Ctx.Slice->getTriple().str(), "-", 159 getName(Ctx.Type), getFileExtension(Ctx.LangMode)}); 160 return llvm::MemoryBuffer::getMemBufferCopy(Contents, BufferName); 161 } 162 163 } // namespace clang::installapi 164