xref: /llvm-project/clang/lib/ExtractAPI/API.cpp (revision 184931853924b53f5f07602229b9d129540ab02a)
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(DenseMap<StringRef, APIRecord *> &USRLookupTable,
31                             APISet::RecordMap<RecordTy> &RecordMap,
32                             StringRef USR, CtorArgsTy &&...CtorArgs) {
33   auto Result = RecordMap.insert({USR, nullptr});
34 
35   // Create the record if it does not already exist
36   if (Result.second)
37     Result.first->second =
38         std::make_unique<RecordTy>(USR, std::forward<CtorArgsTy>(CtorArgs)...);
39 
40   auto *Record = Result.first->second.get();
41   USRLookupTable.insert({USR, Record});
42   return Record;
43 }
44 
45 } // namespace
46 
47 GlobalVariableRecord *
48 APISet::addGlobalVar(StringRef Name, StringRef USR, PresumedLoc Loc,
49                      AvailabilitySet Availabilities, LinkageInfo Linkage,
50                      const DocComment &Comment, DeclarationFragments Fragments,
51                      DeclarationFragments SubHeading, bool IsFromSystemHeader) {
52   return addTopLevelRecord(USRBasedLookupTable, GlobalVariables, USR, Name, Loc,
53                            std::move(Availabilities), Linkage, Comment,
54                            Fragments, SubHeading, IsFromSystemHeader);
55 }
56 
57 GlobalFunctionRecord *APISet::addGlobalFunction(
58     StringRef Name, StringRef USR, PresumedLoc Loc,
59     AvailabilitySet Availabilities, LinkageInfo Linkage,
60     const DocComment &Comment, DeclarationFragments Fragments,
61     DeclarationFragments SubHeading, FunctionSignature Signature,
62     bool IsFromSystemHeader) {
63   return addTopLevelRecord(USRBasedLookupTable, GlobalFunctions, USR, Name, Loc,
64                            std::move(Availabilities), Linkage, Comment,
65                            Fragments, SubHeading, Signature,
66                            IsFromSystemHeader);
67 }
68 
69 EnumConstantRecord *APISet::addEnumConstant(EnumRecord *Enum, StringRef Name,
70                                             StringRef USR, PresumedLoc Loc,
71                                             AvailabilitySet Availabilities,
72                                             const DocComment &Comment,
73                                             DeclarationFragments Declaration,
74                                             DeclarationFragments SubHeading,
75                                             bool IsFromSystemHeader) {
76   auto Record = std::make_unique<EnumConstantRecord>(
77       USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
78       SubHeading, IsFromSystemHeader);
79   Record->ParentInformation = APIRecord::HierarchyInformation(
80       Enum->USR, Enum->Name, Enum->getKind(), Enum);
81   USRBasedLookupTable.insert({USR, Record.get()});
82   return Enum->Constants.emplace_back(std::move(Record)).get();
83 }
84 
85 EnumRecord *APISet::addEnum(StringRef Name, StringRef USR, PresumedLoc Loc,
86                             AvailabilitySet Availabilities,
87                             const DocComment &Comment,
88                             DeclarationFragments Declaration,
89                             DeclarationFragments SubHeading,
90                             bool IsFromSystemHeader) {
91   return addTopLevelRecord(USRBasedLookupTable, Enums, USR, Name, Loc,
92                            std::move(Availabilities), Comment, Declaration,
93                            SubHeading, IsFromSystemHeader);
94 }
95 
96 StructFieldRecord *APISet::addStructField(StructRecord *Struct, StringRef Name,
97                                           StringRef USR, PresumedLoc Loc,
98                                           AvailabilitySet Availabilities,
99                                           const DocComment &Comment,
100                                           DeclarationFragments Declaration,
101                                           DeclarationFragments SubHeading,
102                                           bool IsFromSystemHeader) {
103   auto Record = std::make_unique<StructFieldRecord>(
104       USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
105       SubHeading, IsFromSystemHeader);
106   Record->ParentInformation = APIRecord::HierarchyInformation(
107       Struct->USR, Struct->Name, Struct->getKind(), Struct);
108   USRBasedLookupTable.insert({USR, Record.get()});
109   return Struct->Fields.emplace_back(std::move(Record)).get();
110 }
111 
112 StructRecord *APISet::addStruct(StringRef Name, StringRef USR, PresumedLoc Loc,
113                                 AvailabilitySet Availabilities,
114                                 const DocComment &Comment,
115                                 DeclarationFragments Declaration,
116                                 DeclarationFragments SubHeading,
117                                 bool IsFromSystemHeader) {
118   return addTopLevelRecord(USRBasedLookupTable, Structs, USR, Name, Loc,
119                            std::move(Availabilities), Comment, Declaration,
120                            SubHeading, IsFromSystemHeader);
121 }
122 
123 StaticFieldRecord *
124 APISet::addStaticField(StringRef Name, StringRef USR, PresumedLoc Loc,
125                        AvailabilitySet Availabilities, LinkageInfo Linkage,
126                        const DocComment &Comment,
127                        DeclarationFragments Declaration,
128                        DeclarationFragments SubHeading, SymbolReference Context,
129                        AccessControl Access, bool IsFromSystemHeader) {
130   return addTopLevelRecord(USRBasedLookupTable, StaticFields, USR, Name, Loc,
131                            std::move(Availabilities), Linkage, Comment,
132                            Declaration, SubHeading, Context, Access,
133                            IsFromSystemHeader);
134 }
135 
136 CXXFieldRecord *
137 APISet::addCXXField(CXXClassRecord *CXXClass, StringRef Name, StringRef USR,
138                     PresumedLoc Loc, AvailabilitySet Availabilities,
139                     const DocComment &Comment, DeclarationFragments Declaration,
140                     DeclarationFragments SubHeading, AccessControl Access,
141                     bool IsFromSystemHeader) {
142   auto Record = std::make_unique<CXXFieldRecord>(
143       USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
144       SubHeading, Access, IsFromSystemHeader);
145   Record->ParentInformation = APIRecord::HierarchyInformation(
146       CXXClass->USR, CXXClass->Name, CXXClass->getKind(), CXXClass);
147   USRBasedLookupTable.insert({USR, Record.get()});
148   return CXXClass->Fields.emplace_back(std::move(Record)).get();
149 }
150 
151 CXXClassRecord *
152 APISet::addCXXClass(StringRef Name, StringRef USR, PresumedLoc Loc,
153                     AvailabilitySet Availabilities, const DocComment &Comment,
154                     DeclarationFragments Declaration,
155                     DeclarationFragments SubHeading, APIRecord::RecordKind Kind,
156                     bool IsFromSystemHeader) {
157   return addTopLevelRecord(USRBasedLookupTable, CXXClasses, USR, Name, Loc,
158                            std::move(Availabilities), Comment, Declaration,
159                            SubHeading, Kind, IsFromSystemHeader);
160 }
161 
162 CXXMethodRecord *APISet::addCXXMethod(
163     CXXClassRecord *CXXClassRecord, StringRef Name, StringRef USR,
164     PresumedLoc Loc, AvailabilitySet Availability, const DocComment &Comment,
165     DeclarationFragments Declaration, DeclarationFragments SubHeading,
166     FunctionSignature Signature, bool IsStatic, AccessControl Access,
167     bool IsFromSystemHeader) {
168   std::unique_ptr<CXXMethodRecord> Record;
169   if (IsStatic)
170     Record = std::make_unique<CXXStaticMethodRecord>(
171         USR, Name, Loc, std::move(Availability), Comment, Declaration,
172         SubHeading, Signature, Access, IsFromSystemHeader);
173   else
174     Record = std::make_unique<CXXInstanceMethodRecord>(
175         USR, Name, Loc, std::move(Availability), Comment, Declaration,
176         SubHeading, Signature, Access, IsFromSystemHeader);
177 
178   Record->ParentInformation = APIRecord::HierarchyInformation(
179       CXXClassRecord->USR, CXXClassRecord->Name, CXXClassRecord->getKind(),
180       CXXClassRecord);
181   USRBasedLookupTable.insert({USR, Record.get()});
182   return CXXClassRecord->Methods.emplace_back(std::move(Record)).get();
183 }
184 
185 CXXMethodRecord *APISet::addCXXSpecialMethod(
186     CXXClassRecord *CXXClassRecord, StringRef Name, StringRef USR,
187     PresumedLoc Loc, AvailabilitySet Availability, const DocComment &Comment,
188     DeclarationFragments Declaration, DeclarationFragments SubHeading,
189     FunctionSignature Signature, bool IsConstructor, AccessControl Access,
190     bool IsFromSystemHeader) {
191   std::unique_ptr<CXXMethodRecord> Record;
192   if (IsConstructor)
193     Record = std::make_unique<CXXConstructorRecord>(
194         USR, Name, Loc, std::move(Availability), Comment, Declaration,
195         SubHeading, Signature, Access, IsFromSystemHeader);
196   else
197     Record = std::make_unique<CXXDestructorRecord>(
198         USR, Name, Loc, std::move(Availability), Comment, Declaration,
199         SubHeading, Signature, Access, IsFromSystemHeader);
200 
201   Record->ParentInformation = APIRecord::HierarchyInformation(
202       CXXClassRecord->USR, CXXClassRecord->Name, CXXClassRecord->getKind(),
203       CXXClassRecord);
204   USRBasedLookupTable.insert({USR, Record.get()});
205   return CXXClassRecord->Methods.emplace_back(std::move(Record)).get();
206 }
207 
208 ObjCCategoryRecord *APISet::addObjCCategory(
209     StringRef Name, StringRef USR, PresumedLoc Loc,
210     AvailabilitySet Availabilities, const DocComment &Comment,
211     DeclarationFragments Declaration, DeclarationFragments SubHeading,
212     SymbolReference Interface, bool IsFromSystemHeader,
213     bool IsFromExternalModule) {
214   // Create the category record.
215   auto *Record =
216       addTopLevelRecord(USRBasedLookupTable, ObjCCategories, USR, Name, Loc,
217                         std::move(Availabilities), Comment, Declaration,
218                         SubHeading, Interface, IsFromSystemHeader);
219 
220   Record->IsFromExternalModule = IsFromExternalModule;
221 
222   auto It = ObjCInterfaces.find(Interface.USR);
223   if (It != ObjCInterfaces.end())
224     It->second->Categories.push_back(Record);
225 
226   return Record;
227 }
228 
229 ObjCInterfaceRecord *
230 APISet::addObjCInterface(StringRef Name, StringRef USR, PresumedLoc Loc,
231                          AvailabilitySet Availabilities, LinkageInfo Linkage,
232                          const DocComment &Comment,
233                          DeclarationFragments Declaration,
234                          DeclarationFragments SubHeading,
235                          SymbolReference SuperClass, bool IsFromSystemHeader) {
236   return addTopLevelRecord(USRBasedLookupTable, ObjCInterfaces, USR, Name, Loc,
237                            std::move(Availabilities), Linkage, Comment,
238                            Declaration, SubHeading, SuperClass,
239                            IsFromSystemHeader);
240 }
241 
242 ObjCMethodRecord *APISet::addObjCMethod(
243     ObjCContainerRecord *Container, StringRef Name, StringRef USR,
244     PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment,
245     DeclarationFragments Declaration, DeclarationFragments SubHeading,
246     FunctionSignature Signature, bool IsInstanceMethod,
247     bool IsFromSystemHeader) {
248   std::unique_ptr<ObjCMethodRecord> Record;
249   if (IsInstanceMethod)
250     Record = std::make_unique<ObjCInstanceMethodRecord>(
251         USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
252         SubHeading, Signature, IsFromSystemHeader);
253   else
254     Record = std::make_unique<ObjCClassMethodRecord>(
255         USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
256         SubHeading, Signature, IsFromSystemHeader);
257 
258   Record->ParentInformation = APIRecord::HierarchyInformation(
259       Container->USR, Container->Name, Container->getKind(), Container);
260   USRBasedLookupTable.insert({USR, Record.get()});
261   return Container->Methods.emplace_back(std::move(Record)).get();
262 }
263 
264 ObjCPropertyRecord *APISet::addObjCProperty(
265     ObjCContainerRecord *Container, StringRef Name, StringRef USR,
266     PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment,
267     DeclarationFragments Declaration, DeclarationFragments SubHeading,
268     ObjCPropertyRecord::AttributeKind Attributes, StringRef GetterName,
269     StringRef SetterName, bool IsOptional, bool IsInstanceProperty,
270     bool IsFromSystemHeader) {
271   std::unique_ptr<ObjCPropertyRecord> Record;
272   if (IsInstanceProperty)
273     Record = std::make_unique<ObjCInstancePropertyRecord>(
274         USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
275         SubHeading, Attributes, GetterName, SetterName, IsOptional,
276         IsFromSystemHeader);
277   else
278     Record = std::make_unique<ObjCClassPropertyRecord>(
279         USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
280         SubHeading, Attributes, GetterName, SetterName, IsOptional,
281         IsFromSystemHeader);
282   Record->ParentInformation = APIRecord::HierarchyInformation(
283       Container->USR, Container->Name, Container->getKind(), Container);
284   USRBasedLookupTable.insert({USR, Record.get()});
285   return Container->Properties.emplace_back(std::move(Record)).get();
286 }
287 
288 ObjCInstanceVariableRecord *APISet::addObjCInstanceVariable(
289     ObjCContainerRecord *Container, StringRef Name, StringRef USR,
290     PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment,
291     DeclarationFragments Declaration, DeclarationFragments SubHeading,
292     ObjCInstanceVariableRecord::AccessControl Access, bool IsFromSystemHeader) {
293   auto Record = std::make_unique<ObjCInstanceVariableRecord>(
294       USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
295       SubHeading, Access, IsFromSystemHeader);
296   Record->ParentInformation = APIRecord::HierarchyInformation(
297       Container->USR, Container->Name, Container->getKind(), Container);
298   USRBasedLookupTable.insert({USR, Record.get()});
299   return Container->Ivars.emplace_back(std::move(Record)).get();
300 }
301 
302 ObjCProtocolRecord *APISet::addObjCProtocol(StringRef Name, StringRef USR,
303                                             PresumedLoc Loc,
304                                             AvailabilitySet Availabilities,
305                                             const DocComment &Comment,
306                                             DeclarationFragments Declaration,
307                                             DeclarationFragments SubHeading,
308                                             bool IsFromSystemHeader) {
309   return addTopLevelRecord(USRBasedLookupTable, ObjCProtocols, USR, Name, Loc,
310                            std::move(Availabilities), Comment, Declaration,
311                            SubHeading, IsFromSystemHeader);
312 }
313 
314 MacroDefinitionRecord *
315 APISet::addMacroDefinition(StringRef Name, StringRef USR, PresumedLoc Loc,
316                            DeclarationFragments Declaration,
317                            DeclarationFragments SubHeading,
318                            bool IsFromSystemHeader) {
319   return addTopLevelRecord(USRBasedLookupTable, Macros, USR, Name, Loc,
320                            Declaration, SubHeading, IsFromSystemHeader);
321 }
322 
323 TypedefRecord *
324 APISet::addTypedef(StringRef Name, StringRef USR, PresumedLoc Loc,
325                    AvailabilitySet Availabilities, const DocComment &Comment,
326                    DeclarationFragments Declaration,
327                    DeclarationFragments SubHeading,
328                    SymbolReference UnderlyingType, bool IsFromSystemHeader) {
329   return addTopLevelRecord(USRBasedLookupTable, Typedefs, USR, Name, Loc,
330                            std::move(Availabilities), Comment, Declaration,
331                            SubHeading, UnderlyingType, IsFromSystemHeader);
332 }
333 
334 APIRecord *APISet::findRecordForUSR(StringRef USR) const {
335   if (USR.empty())
336     return nullptr;
337 
338   return USRBasedLookupTable.lookup(USR);
339 }
340 
341 StringRef APISet::recordUSR(const Decl *D) {
342   SmallString<128> USR;
343   index::generateUSRForDecl(D, USR);
344   return copyString(USR);
345 }
346 
347 StringRef APISet::recordUSRForMacro(StringRef Name, SourceLocation SL,
348                                     const SourceManager &SM) {
349   SmallString<128> USR;
350   index::generateUSRForMacro(Name, SL, SM, USR);
351   return copyString(USR);
352 }
353 
354 StringRef APISet::copyString(StringRef String) {
355   if (String.empty())
356     return {};
357 
358   // No need to allocate memory and copy if the string has already been stored.
359   if (StringAllocator.identifyObject(String.data()))
360     return String;
361 
362   void *Ptr = StringAllocator.Allocate(String.size(), 1);
363   memcpy(Ptr, String.data(), String.size());
364   return StringRef(reinterpret_cast<const char *>(Ptr), String.size());
365 }
366 
367 APIRecord::~APIRecord() {}
368 ObjCContainerRecord::~ObjCContainerRecord() {}
369 ObjCMethodRecord::~ObjCMethodRecord() {}
370 ObjCPropertyRecord::~ObjCPropertyRecord() {}
371 CXXMethodRecord::~CXXMethodRecord() {}
372 
373 void GlobalFunctionRecord::anchor() {}
374 void GlobalVariableRecord::anchor() {}
375 void EnumConstantRecord::anchor() {}
376 void EnumRecord::anchor() {}
377 void StructFieldRecord::anchor() {}
378 void StructRecord::anchor() {}
379 void CXXFieldRecord::anchor() {}
380 void CXXClassRecord::anchor() {}
381 void CXXConstructorRecord::anchor() {}
382 void CXXDestructorRecord::anchor() {}
383 void CXXInstanceMethodRecord::anchor() {}
384 void CXXStaticMethodRecord::anchor() {}
385 void ObjCInstancePropertyRecord::anchor() {}
386 void ObjCClassPropertyRecord::anchor() {}
387 void ObjCInstanceVariableRecord::anchor() {}
388 void ObjCInstanceMethodRecord::anchor() {}
389 void ObjCClassMethodRecord::anchor() {}
390 void ObjCCategoryRecord::anchor() {}
391 void ObjCInterfaceRecord::anchor() {}
392 void ObjCProtocolRecord::anchor() {}
393 void MacroDefinitionRecord::anchor() {}
394 void TypedefRecord::anchor() {}
395