xref: /llvm-project/clang/lib/ExtractAPI/API.cpp (revision f63db9159bbbb0db98e13cb4440fdaa5c40e219b)
1 //===- ExtractAPI/API.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 /// \file
10 /// This file implements the APIRecord and derived record structs,
11 /// and the APISet class.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #include "clang/ExtractAPI/API.h"
16 #include "clang/AST/CommentCommandTraits.h"
17 #include "clang/AST/CommentLexer.h"
18 #include "clang/AST/RawCommentList.h"
19 #include "clang/Index/USRGeneration.h"
20 #include "llvm/ADT/STLFunctionalExtras.h"
21 #include "llvm/ADT/StringRef.h"
22 #include <memory>
23 
24 using namespace clang::extractapi;
25 using namespace llvm;
26 
27 namespace {
28 
29 template <typename RecordTy, typename... CtorArgsTy>
30 RecordTy *addTopLevelRecord(APISet::RecordMap<RecordTy> &RecordMap,
31                             StringRef USR, CtorArgsTy &&...CtorArgs) {
32   auto Result = RecordMap.insert({USR, nullptr});
33 
34   // Create the record if it does not already exist
35   if (Result.second)
36     Result.first->second =
37         std::make_unique<RecordTy>(USR, std::forward<CtorArgsTy>(CtorArgs)...);
38 
39   return Result.first->second.get();
40 }
41 
42 } // namespace
43 
44 GlobalVariableRecord *
45 APISet::addGlobalVar(StringRef Name, StringRef USR, PresumedLoc Loc,
46                      AvailabilitySet Availabilities, LinkageInfo Linkage,
47                      const DocComment &Comment, DeclarationFragments Fragments,
48                      DeclarationFragments SubHeading) {
49   return addTopLevelRecord(GlobalVariables, USR, Name, Loc,
50                            std::move(Availabilities), Linkage, Comment,
51                            Fragments, SubHeading);
52 }
53 
54 GlobalFunctionRecord *APISet::addGlobalFunction(
55     StringRef Name, StringRef USR, PresumedLoc Loc,
56     AvailabilitySet Availabilities, LinkageInfo Linkage,
57     const DocComment &Comment, DeclarationFragments Fragments,
58     DeclarationFragments SubHeading, FunctionSignature Signature) {
59   return addTopLevelRecord(GlobalFunctions, USR, Name, Loc,
60                            std::move(Availabilities), Linkage, Comment,
61                            Fragments, SubHeading, Signature);
62 }
63 
64 EnumConstantRecord *APISet::addEnumConstant(EnumRecord *Enum, StringRef Name,
65                                             StringRef USR, PresumedLoc Loc,
66                                             AvailabilitySet Availabilities,
67                                             const DocComment &Comment,
68                                             DeclarationFragments Declaration,
69                                             DeclarationFragments SubHeading) {
70   auto Record = std::make_unique<EnumConstantRecord>(
71       USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
72       SubHeading);
73   return Enum->Constants.emplace_back(std::move(Record)).get();
74 }
75 
76 EnumRecord *APISet::addEnum(StringRef Name, StringRef USR, PresumedLoc Loc,
77                             AvailabilitySet Availabilities,
78                             const DocComment &Comment,
79                             DeclarationFragments Declaration,
80                             DeclarationFragments SubHeading) {
81   return addTopLevelRecord(Enums, USR, Name, Loc, std::move(Availabilities),
82                            Comment, Declaration, SubHeading);
83 }
84 
85 StructFieldRecord *APISet::addStructField(StructRecord *Struct, StringRef Name,
86                                           StringRef USR, PresumedLoc Loc,
87                                           AvailabilitySet Availabilities,
88                                           const DocComment &Comment,
89                                           DeclarationFragments Declaration,
90                                           DeclarationFragments SubHeading) {
91   auto Record = std::make_unique<StructFieldRecord>(
92       USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
93       SubHeading);
94   return Struct->Fields.emplace_back(std::move(Record)).get();
95 }
96 
97 StructRecord *APISet::addStruct(StringRef Name, StringRef USR, PresumedLoc Loc,
98                                 AvailabilitySet Availabilities,
99                                 const DocComment &Comment,
100                                 DeclarationFragments Declaration,
101                                 DeclarationFragments SubHeading) {
102   return addTopLevelRecord(Structs, USR, Name, Loc, std::move(Availabilities),
103                            Comment, Declaration, SubHeading);
104 }
105 
106 ObjCCategoryRecord *APISet::addObjCCategory(StringRef Name, StringRef USR,
107                                             PresumedLoc Loc,
108                                             AvailabilitySet Availabilities,
109                                             const DocComment &Comment,
110                                             DeclarationFragments Declaration,
111                                             DeclarationFragments SubHeading,
112                                             SymbolReference Interface) {
113   // Create the category record.
114   auto *Record = addTopLevelRecord(ObjCCategories, USR, Name, Loc,
115                                    std::move(Availabilities), Comment,
116                                    Declaration, SubHeading, Interface);
117 
118   // If this category is extending a known interface, associate it with the
119   // ObjCInterfaceRecord.
120   auto It = ObjCInterfaces.find(Interface.USR);
121   if (It != ObjCInterfaces.end())
122     It->second->Categories.push_back(Record);
123 
124   return Record;
125 }
126 
127 ObjCInterfaceRecord *APISet::addObjCInterface(
128     StringRef Name, StringRef USR, PresumedLoc Loc,
129     AvailabilitySet Availabilities, LinkageInfo Linkage,
130     const DocComment &Comment, DeclarationFragments Declaration,
131     DeclarationFragments SubHeading, SymbolReference SuperClass) {
132   return addTopLevelRecord(ObjCInterfaces, USR, Name, Loc,
133                            std::move(Availabilities), Linkage, Comment,
134                            Declaration, SubHeading, SuperClass);
135 }
136 
137 ObjCMethodRecord *APISet::addObjCMethod(
138     ObjCContainerRecord *Container, StringRef Name, StringRef USR,
139     PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment,
140     DeclarationFragments Declaration, DeclarationFragments SubHeading,
141     FunctionSignature Signature, bool IsInstanceMethod) {
142   auto Record = std::make_unique<ObjCMethodRecord>(
143       USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
144       SubHeading, Signature, IsInstanceMethod);
145   return Container->Methods.emplace_back(std::move(Record)).get();
146 }
147 
148 ObjCPropertyRecord *APISet::addObjCProperty(
149     ObjCContainerRecord *Container, StringRef Name, StringRef USR,
150     PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment,
151     DeclarationFragments Declaration, DeclarationFragments SubHeading,
152     ObjCPropertyRecord::AttributeKind Attributes, StringRef GetterName,
153     StringRef SetterName, bool IsOptional) {
154   auto Record = std::make_unique<ObjCPropertyRecord>(
155       USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
156       SubHeading, Attributes, GetterName, SetterName, IsOptional);
157   return Container->Properties.emplace_back(std::move(Record)).get();
158 }
159 
160 ObjCInstanceVariableRecord *APISet::addObjCInstanceVariable(
161     ObjCContainerRecord *Container, StringRef Name, StringRef USR,
162     PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment,
163     DeclarationFragments Declaration, DeclarationFragments SubHeading,
164     ObjCInstanceVariableRecord::AccessControl Access) {
165   auto Record = std::make_unique<ObjCInstanceVariableRecord>(
166       USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
167       SubHeading, Access);
168   return Container->Ivars.emplace_back(std::move(Record)).get();
169 }
170 
171 ObjCProtocolRecord *APISet::addObjCProtocol(StringRef Name, StringRef USR,
172                                             PresumedLoc Loc,
173                                             AvailabilitySet Availabilities,
174                                             const DocComment &Comment,
175                                             DeclarationFragments Declaration,
176                                             DeclarationFragments SubHeading) {
177   return addTopLevelRecord(ObjCProtocols, USR, Name, Loc,
178                            std::move(Availabilities), Comment, Declaration,
179                            SubHeading);
180 }
181 
182 MacroDefinitionRecord *
183 APISet::addMacroDefinition(StringRef Name, StringRef USR, PresumedLoc Loc,
184                            DeclarationFragments Declaration,
185                            DeclarationFragments SubHeading) {
186   return addTopLevelRecord(Macros, USR, Name, Loc, Declaration, SubHeading);
187 }
188 
189 TypedefRecord *APISet::addTypedef(StringRef Name, StringRef USR,
190                                   PresumedLoc Loc,
191                                   AvailabilitySet Availabilities,
192                                   const DocComment &Comment,
193                                   DeclarationFragments Declaration,
194                                   DeclarationFragments SubHeading,
195                                   SymbolReference UnderlyingType) {
196   return addTopLevelRecord(Typedefs, USR, Name, Loc, std::move(Availabilities),
197                            Comment, Declaration, SubHeading, UnderlyingType);
198 }
199 
200 template <class RecordMap>
201 static APIRecord *getSymbolInRecordMapForUSR(StringRef USR,
202                                              const RecordMap &Records) {
203   auto It = Records.find(USR);
204   return (It != Records.end() ? It->second.get() : nullptr);
205 }
206 
207 APIRecord *APISet::getSymbolForUSR(StringRef USR) const {
208   if (USR.empty())
209     return nullptr;
210   if (auto *Record = getSymbolInRecordMapForUSR(USR, ObjCProtocols))
211     return Record;
212   if (auto *Record = getSymbolInRecordMapForUSR(USR, ObjCInterfaces))
213     return Record;
214   if (auto *Record = getSymbolInRecordMapForUSR(USR, ObjCCategories))
215     return Record;
216   if (auto *Record = getSymbolInRecordMapForUSR(USR, ObjCCategories))
217     return Record;
218   if (auto *Record = getSymbolInRecordMapForUSR(USR, Structs))
219     return Record;
220   if (auto *Record = getSymbolInRecordMapForUSR(USR, Enums))
221     return Record;
222   if (auto *Record = getSymbolInRecordMapForUSR(USR, Typedefs))
223     return Record;
224   if (auto *Record = getSymbolInRecordMapForUSR(USR, GlobalFunctions))
225     return Record;
226   if (auto *Record = getSymbolInRecordMapForUSR(USR, GlobalVariables))
227     return Record;
228   if (auto *Record = getSymbolInRecordMapForUSR(USR, Macros))
229     return Record;
230   return nullptr;
231 }
232 
233 StringRef APISet::recordUSR(const Decl *D) {
234   SmallString<128> USR;
235   index::generateUSRForDecl(D, USR);
236   return copyString(USR);
237 }
238 
239 StringRef APISet::recordUSRForMacro(StringRef Name, SourceLocation SL,
240                                     const SourceManager &SM) {
241   SmallString<128> USR;
242   index::generateUSRForMacro(Name, SL, SM, USR);
243   return copyString(USR);
244 }
245 
246 StringRef APISet::copyString(StringRef String) {
247   if (String.empty())
248     return {};
249 
250   // No need to allocate memory and copy if the string has already been stored.
251   if (StringAllocator.identifyObject(String.data()))
252     return String;
253 
254   void *Ptr = StringAllocator.Allocate(String.size(), 1);
255   memcpy(Ptr, String.data(), String.size());
256   return StringRef(reinterpret_cast<const char *>(Ptr), String.size());
257 }
258 
259 APIRecord::~APIRecord() {}
260 
261 ObjCContainerRecord::~ObjCContainerRecord() {}
262 
263 void GlobalFunctionRecord::anchor() {}
264 void GlobalVariableRecord::anchor() {}
265 void EnumConstantRecord::anchor() {}
266 void EnumRecord::anchor() {}
267 void StructFieldRecord::anchor() {}
268 void StructRecord::anchor() {}
269 void ObjCPropertyRecord::anchor() {}
270 void ObjCInstanceVariableRecord::anchor() {}
271 void ObjCMethodRecord::anchor() {}
272 void ObjCCategoryRecord::anchor() {}
273 void ObjCInterfaceRecord::anchor() {}
274 void ObjCProtocolRecord::anchor() {}
275 void MacroDefinitionRecord::anchor() {}
276 void TypedefRecord::anchor() {}
277