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 ObjCCategoryRecord *APISet::addObjCCategory(
124     StringRef Name, StringRef USR, PresumedLoc Loc,
125     AvailabilitySet Availabilities, const DocComment &Comment,
126     DeclarationFragments Declaration, DeclarationFragments SubHeading,
127     SymbolReference Interface, bool IsFromSystemHeader) {
128   // Create the category record.
129   auto *Record =
130       addTopLevelRecord(USRBasedLookupTable, ObjCCategories, USR, Name, Loc,
131                         std::move(Availabilities), Comment, Declaration,
132                         SubHeading, Interface, IsFromSystemHeader);
133 
134   // If this category is extending a known interface, associate it with the
135   // ObjCInterfaceRecord.
136   auto It = ObjCInterfaces.find(Interface.USR);
137   if (It != ObjCInterfaces.end())
138     It->second->Categories.push_back(Record);
139 
140   return Record;
141 }
142 
143 ObjCInterfaceRecord *
144 APISet::addObjCInterface(StringRef Name, StringRef USR, PresumedLoc Loc,
145                          AvailabilitySet Availabilities, LinkageInfo Linkage,
146                          const DocComment &Comment,
147                          DeclarationFragments Declaration,
148                          DeclarationFragments SubHeading,
149                          SymbolReference SuperClass, bool IsFromSystemHeader) {
150   return addTopLevelRecord(USRBasedLookupTable, ObjCInterfaces, USR, Name, Loc,
151                            std::move(Availabilities), Linkage, Comment,
152                            Declaration, SubHeading, SuperClass,
153                            IsFromSystemHeader);
154 }
155 
156 ObjCMethodRecord *APISet::addObjCMethod(
157     ObjCContainerRecord *Container, StringRef Name, StringRef USR,
158     PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment,
159     DeclarationFragments Declaration, DeclarationFragments SubHeading,
160     FunctionSignature Signature, bool IsInstanceMethod,
161     bool IsFromSystemHeader) {
162   std::unique_ptr<ObjCMethodRecord> Record;
163   if (IsInstanceMethod)
164     Record = std::make_unique<ObjCInstanceMethodRecord>(
165         USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
166         SubHeading, Signature, IsFromSystemHeader);
167   else
168     Record = std::make_unique<ObjCClassMethodRecord>(
169         USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
170         SubHeading, Signature, IsFromSystemHeader);
171 
172   Record->ParentInformation = APIRecord::HierarchyInformation(
173       Container->USR, Container->Name, Container->getKind(), Container);
174   USRBasedLookupTable.insert({USR, Record.get()});
175   return Container->Methods.emplace_back(std::move(Record)).get();
176 }
177 
178 ObjCPropertyRecord *APISet::addObjCProperty(
179     ObjCContainerRecord *Container, StringRef Name, StringRef USR,
180     PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment,
181     DeclarationFragments Declaration, DeclarationFragments SubHeading,
182     ObjCPropertyRecord::AttributeKind Attributes, StringRef GetterName,
183     StringRef SetterName, bool IsOptional, bool IsInstanceProperty,
184     bool IsFromSystemHeader) {
185   std::unique_ptr<ObjCPropertyRecord> Record;
186   if (IsInstanceProperty)
187     Record = std::make_unique<ObjCInstancePropertyRecord>(
188         USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
189         SubHeading, Attributes, GetterName, SetterName, IsOptional,
190         IsFromSystemHeader);
191   else
192     Record = std::make_unique<ObjCClassPropertyRecord>(
193         USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
194         SubHeading, Attributes, GetterName, SetterName, IsOptional,
195         IsFromSystemHeader);
196   Record->ParentInformation = APIRecord::HierarchyInformation(
197       Container->USR, Container->Name, Container->getKind(), Container);
198   USRBasedLookupTable.insert({USR, Record.get()});
199   return Container->Properties.emplace_back(std::move(Record)).get();
200 }
201 
202 ObjCInstanceVariableRecord *APISet::addObjCInstanceVariable(
203     ObjCContainerRecord *Container, StringRef Name, StringRef USR,
204     PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment,
205     DeclarationFragments Declaration, DeclarationFragments SubHeading,
206     ObjCInstanceVariableRecord::AccessControl Access, bool IsFromSystemHeader) {
207   auto Record = std::make_unique<ObjCInstanceVariableRecord>(
208       USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
209       SubHeading, Access, IsFromSystemHeader);
210   Record->ParentInformation = APIRecord::HierarchyInformation(
211       Container->USR, Container->Name, Container->getKind(), Container);
212   USRBasedLookupTable.insert({USR, Record.get()});
213   return Container->Ivars.emplace_back(std::move(Record)).get();
214 }
215 
216 ObjCProtocolRecord *APISet::addObjCProtocol(StringRef Name, StringRef USR,
217                                             PresumedLoc Loc,
218                                             AvailabilitySet Availabilities,
219                                             const DocComment &Comment,
220                                             DeclarationFragments Declaration,
221                                             DeclarationFragments SubHeading,
222                                             bool IsFromSystemHeader) {
223   return addTopLevelRecord(USRBasedLookupTable, ObjCProtocols, USR, Name, Loc,
224                            std::move(Availabilities), Comment, Declaration,
225                            SubHeading, IsFromSystemHeader);
226 }
227 
228 MacroDefinitionRecord *
229 APISet::addMacroDefinition(StringRef Name, StringRef USR, PresumedLoc Loc,
230                            DeclarationFragments Declaration,
231                            DeclarationFragments SubHeading,
232                            bool IsFromSystemHeader) {
233   return addTopLevelRecord(USRBasedLookupTable, Macros, USR, Name, Loc,
234                            Declaration, SubHeading, IsFromSystemHeader);
235 }
236 
237 TypedefRecord *
238 APISet::addTypedef(StringRef Name, StringRef USR, PresumedLoc Loc,
239                    AvailabilitySet Availabilities, const DocComment &Comment,
240                    DeclarationFragments Declaration,
241                    DeclarationFragments SubHeading,
242                    SymbolReference UnderlyingType, bool IsFromSystemHeader) {
243   return addTopLevelRecord(USRBasedLookupTable, Typedefs, USR, Name, Loc,
244                            std::move(Availabilities), Comment, Declaration,
245                            SubHeading, UnderlyingType, IsFromSystemHeader);
246 }
247 
248 APIRecord *APISet::findRecordForUSR(StringRef USR) const {
249   if (USR.empty())
250     return nullptr;
251 
252   auto It = USRBasedLookupTable.find(USR);
253   if (It != USRBasedLookupTable.end())
254     return It->second;
255   return nullptr;
256 }
257 
258 StringRef APISet::recordUSR(const Decl *D) {
259   SmallString<128> USR;
260   index::generateUSRForDecl(D, USR);
261   return copyString(USR);
262 }
263 
264 StringRef APISet::recordUSRForMacro(StringRef Name, SourceLocation SL,
265                                     const SourceManager &SM) {
266   SmallString<128> USR;
267   index::generateUSRForMacro(Name, SL, SM, USR);
268   return copyString(USR);
269 }
270 
271 StringRef APISet::copyString(StringRef String) {
272   if (String.empty())
273     return {};
274 
275   // No need to allocate memory and copy if the string has already been stored.
276   if (StringAllocator.identifyObject(String.data()))
277     return String;
278 
279   void *Ptr = StringAllocator.Allocate(String.size(), 1);
280   memcpy(Ptr, String.data(), String.size());
281   return StringRef(reinterpret_cast<const char *>(Ptr), String.size());
282 }
283 
284 APIRecord::~APIRecord() {}
285 ObjCContainerRecord::~ObjCContainerRecord() {}
286 ObjCMethodRecord::~ObjCMethodRecord() {}
287 ObjCPropertyRecord::~ObjCPropertyRecord() {}
288 
289 void GlobalFunctionRecord::anchor() {}
290 void GlobalVariableRecord::anchor() {}
291 void EnumConstantRecord::anchor() {}
292 void EnumRecord::anchor() {}
293 void StructFieldRecord::anchor() {}
294 void StructRecord::anchor() {}
295 void ObjCInstancePropertyRecord::anchor() {}
296 void ObjCClassPropertyRecord::anchor() {}
297 void ObjCInstanceVariableRecord::anchor() {}
298 void ObjCInstanceMethodRecord::anchor() {}
299 void ObjCClassMethodRecord::anchor() {}
300 void ObjCCategoryRecord::anchor() {}
301 void ObjCInterfaceRecord::anchor() {}
302 void ObjCProtocolRecord::anchor() {}
303 void MacroDefinitionRecord::anchor() {}
304 void TypedefRecord::anchor() {}
305