xref: /llvm-project/clang/lib/ExtractAPI/API.cpp (revision 39dbfa72aaebe64e913d65f1eeab48c5f33b8010)
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 StringRef APISet::recordUSR(const Decl *D) {
201   SmallString<128> USR;
202   index::generateUSRForDecl(D, USR);
203   return copyString(USR);
204 }
205 
206 StringRef APISet::recordUSRForMacro(StringRef Name, SourceLocation SL,
207                                     const SourceManager &SM) {
208   SmallString<128> USR;
209   index::generateUSRForMacro(Name, SL, SM, USR);
210   return copyString(USR);
211 }
212 
213 StringRef APISet::copyString(StringRef String) {
214   if (String.empty())
215     return {};
216 
217   // No need to allocate memory and copy if the string has already been stored.
218   if (StringAllocator.identifyObject(String.data()))
219     return String;
220 
221   void *Ptr = StringAllocator.Allocate(String.size(), 1);
222   memcpy(Ptr, String.data(), String.size());
223   return StringRef(reinterpret_cast<const char *>(Ptr), String.size());
224 }
225 
226 APIRecord::~APIRecord() {}
227 
228 ObjCContainerRecord::~ObjCContainerRecord() {}
229 
230 void GlobalFunctionRecord::anchor() {}
231 void GlobalVariableRecord::anchor() {}
232 void EnumConstantRecord::anchor() {}
233 void EnumRecord::anchor() {}
234 void StructFieldRecord::anchor() {}
235 void StructRecord::anchor() {}
236 void ObjCPropertyRecord::anchor() {}
237 void ObjCInstanceVariableRecord::anchor() {}
238 void ObjCMethodRecord::anchor() {}
239 void ObjCCategoryRecord::anchor() {}
240 void ObjCInterfaceRecord::anchor() {}
241 void ObjCProtocolRecord::anchor() {}
242 void MacroDefinitionRecord::anchor() {}
243 void TypedefRecord::anchor() {}
244