xref: /llvm-project/clang/lib/InstallAPI/Frontend.cpp (revision 2c93beccdf8e026534a737eddaf8f5f26f3a23c3)
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() << ">\n";
141     else
142       OS << "\"" << H.getPath() << "\"\n";
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