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
24using namespace clang::extractapi;
25using namespace llvm;
26
27namespace {
28
29template <typename RecordTy, typename... CtorArgsTy>
30RecordTy *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
47GlobalVariableRecord *
48APISet::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
57GlobalFunctionRecord *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
69EnumConstantRecord *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
85EnumRecord *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
96StructFieldRecord *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
112StructRecord *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
123ObjCCategoryRecord *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
143ObjCInterfaceRecord *
144APISet::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
156ObjCMethodRecord *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
178ObjCPropertyRecord *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
202ObjCInstanceVariableRecord *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
216ObjCProtocolRecord *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
228MacroDefinitionRecord *
229APISet::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
237TypedefRecord *
238APISet::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
248APIRecord *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
258StringRef APISet::recordUSR(const Decl *D) {
259  SmallString<128> USR;
260  index::generateUSRForDecl(D, USR);
261  return copyString(USR);
262}
263
264StringRef 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
271StringRef 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
284APIRecord::~APIRecord() {}
285ObjCContainerRecord::~ObjCContainerRecord() {}
286ObjCMethodRecord::~ObjCMethodRecord() {}
287ObjCPropertyRecord::~ObjCPropertyRecord() {}
288
289void GlobalFunctionRecord::anchor() {}
290void GlobalVariableRecord::anchor() {}
291void EnumConstantRecord::anchor() {}
292void EnumRecord::anchor() {}
293void StructFieldRecord::anchor() {}
294void StructRecord::anchor() {}
295void ObjCInstancePropertyRecord::anchor() {}
296void ObjCClassPropertyRecord::anchor() {}
297void ObjCInstanceVariableRecord::anchor() {}
298void ObjCInstanceMethodRecord::anchor() {}
299void ObjCClassMethodRecord::anchor() {}
300void ObjCCategoryRecord::anchor() {}
301void ObjCInterfaceRecord::anchor() {}
302void ObjCProtocolRecord::anchor() {}
303void MacroDefinitionRecord::anchor() {}
304void TypedefRecord::anchor() {}
305