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