xref: /llvm-project/clang/lib/InstallAPI/Frontend.cpp (revision 2d7df3167b12e3f3330a6b6e2f83715f8bbad67e)
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