xref: /llvm-project/clang/lib/ExtractAPI/API.cpp (revision 178aad9b946e3c5abe9df162e5c482fb4acae99c)
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 Name, CtorArgsTy &&...CtorArgs) {
32   auto Result = RecordMap.insert({Name, 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>(Name, std::forward<CtorArgsTy>(CtorArgs)...);
38 
39   return Result.first->second.get();
40 }
41 
42 } // namespace
43 
44 GlobalRecord *APISet::addGlobal(GVKind Kind, StringRef Name, StringRef USR,
45                                 PresumedLoc Loc,
46                                 const AvailabilityInfo &Availability,
47                                 LinkageInfo Linkage, const DocComment &Comment,
48                                 DeclarationFragments Fragments,
49                                 DeclarationFragments SubHeading,
50                                 FunctionSignature Signature) {
51   return addTopLevelRecord(Globals, Name, USR, Loc, Availability, Linkage,
52                            Comment, Fragments, SubHeading, Kind, Signature);
53 }
54 
55 GlobalRecord *
56 APISet::addGlobalVar(StringRef Name, StringRef USR, PresumedLoc Loc,
57                      const AvailabilityInfo &Availability, LinkageInfo Linkage,
58                      const DocComment &Comment, DeclarationFragments Fragments,
59                      DeclarationFragments SubHeading) {
60   return addGlobal(GVKind::Variable, Name, USR, Loc, Availability, Linkage,
61                    Comment, Fragments, SubHeading, {});
62 }
63 
64 GlobalRecord *
65 APISet::addFunction(StringRef Name, StringRef USR, PresumedLoc Loc,
66                     const AvailabilityInfo &Availability, LinkageInfo Linkage,
67                     const DocComment &Comment, DeclarationFragments Fragments,
68                     DeclarationFragments SubHeading,
69                     FunctionSignature Signature) {
70   return addGlobal(GVKind::Function, Name, USR, Loc, Availability, Linkage,
71                    Comment, Fragments, SubHeading, Signature);
72 }
73 
74 EnumConstantRecord *APISet::addEnumConstant(
75     EnumRecord *Enum, StringRef Name, StringRef USR, PresumedLoc Loc,
76     const AvailabilityInfo &Availability, const DocComment &Comment,
77     DeclarationFragments Declaration, DeclarationFragments SubHeading) {
78   auto Record = std::make_unique<EnumConstantRecord>(
79       Name, USR, Loc, Availability, Comment, Declaration, SubHeading);
80   return Enum->Constants.emplace_back(std::move(Record)).get();
81 }
82 
83 EnumRecord *APISet::addEnum(StringRef Name, StringRef USR, PresumedLoc Loc,
84                             const AvailabilityInfo &Availability,
85                             const DocComment &Comment,
86                             DeclarationFragments Declaration,
87                             DeclarationFragments SubHeading) {
88   return addTopLevelRecord(Enums, Name, USR, Loc, Availability, Comment,
89                            Declaration, SubHeading);
90 }
91 
92 StructFieldRecord *APISet::addStructField(StructRecord *Struct, StringRef Name,
93                                           StringRef USR, PresumedLoc Loc,
94                                           const AvailabilityInfo &Availability,
95                                           const DocComment &Comment,
96                                           DeclarationFragments Declaration,
97                                           DeclarationFragments SubHeading) {
98   auto Record = std::make_unique<StructFieldRecord>(
99       Name, USR, Loc, Availability, Comment, Declaration, SubHeading);
100   return Struct->Fields.emplace_back(std::move(Record)).get();
101 }
102 
103 StructRecord *APISet::addStruct(StringRef Name, StringRef USR, PresumedLoc Loc,
104                                 const AvailabilityInfo &Availability,
105                                 const DocComment &Comment,
106                                 DeclarationFragments Declaration,
107                                 DeclarationFragments SubHeading) {
108   return addTopLevelRecord(Structs, Name, USR, Loc, Availability, Comment,
109                            Declaration, SubHeading);
110 }
111 
112 ObjCCategoryRecord *APISet::addObjCCategory(
113     StringRef Name, StringRef USR, PresumedLoc Loc,
114     const AvailabilityInfo &Availability, const DocComment &Comment,
115     DeclarationFragments Declaration, DeclarationFragments SubHeading,
116     SymbolReference Interface) {
117   // Create the category record.
118   auto *Record = addTopLevelRecord(ObjCCategories, Name, USR, Loc, Availability,
119                                    Comment, Declaration, SubHeading, Interface);
120 
121   // If this category is extending a known interface, associate it with the
122   // ObjCInterfaceRecord.
123   auto It = ObjCInterfaces.find(Interface.Name);
124   if (It != ObjCInterfaces.end())
125     It->second->Categories.push_back(Record);
126 
127   return Record;
128 }
129 
130 ObjCInterfaceRecord *APISet::addObjCInterface(
131     StringRef Name, StringRef USR, PresumedLoc Loc,
132     const AvailabilityInfo &Availability, LinkageInfo Linkage,
133     const DocComment &Comment, DeclarationFragments Declaration,
134     DeclarationFragments SubHeading, SymbolReference SuperClass) {
135   return addTopLevelRecord(ObjCInterfaces, Name, USR, Loc, Availability,
136                            Linkage, Comment, Declaration, SubHeading,
137                            SuperClass);
138 }
139 
140 ObjCMethodRecord *APISet::addObjCMethod(
141     ObjCContainerRecord *Container, StringRef Name, StringRef USR,
142     PresumedLoc Loc, const AvailabilityInfo &Availability,
143     const DocComment &Comment, DeclarationFragments Declaration,
144     DeclarationFragments SubHeading, FunctionSignature Signature,
145     bool IsInstanceMethod) {
146   auto Record = std::make_unique<ObjCMethodRecord>(
147       Name, USR, Loc, Availability, Comment, Declaration, SubHeading, Signature,
148       IsInstanceMethod);
149   return Container->Methods.emplace_back(std::move(Record)).get();
150 }
151 
152 ObjCPropertyRecord *APISet::addObjCProperty(
153     ObjCContainerRecord *Container, StringRef Name, StringRef USR,
154     PresumedLoc Loc, const AvailabilityInfo &Availability,
155     const DocComment &Comment, DeclarationFragments Declaration,
156     DeclarationFragments SubHeading,
157     ObjCPropertyRecord::AttributeKind Attributes, StringRef GetterName,
158     StringRef SetterName, bool IsOptional) {
159   auto Record = std::make_unique<ObjCPropertyRecord>(
160       Name, USR, Loc, Availability, Comment, Declaration, SubHeading,
161       Attributes, GetterName, SetterName, IsOptional);
162   return Container->Properties.emplace_back(std::move(Record)).get();
163 }
164 
165 ObjCInstanceVariableRecord *APISet::addObjCInstanceVariable(
166     ObjCContainerRecord *Container, StringRef Name, StringRef USR,
167     PresumedLoc Loc, const AvailabilityInfo &Availability,
168     const DocComment &Comment, DeclarationFragments Declaration,
169     DeclarationFragments SubHeading,
170     ObjCInstanceVariableRecord::AccessControl Access) {
171   auto Record = std::make_unique<ObjCInstanceVariableRecord>(
172       Name, USR, Loc, Availability, Comment, Declaration, SubHeading, Access);
173   return Container->Ivars.emplace_back(std::move(Record)).get();
174 }
175 
176 ObjCProtocolRecord *APISet::addObjCProtocol(
177     StringRef Name, StringRef USR, PresumedLoc Loc,
178     const AvailabilityInfo &Availability, const DocComment &Comment,
179     DeclarationFragments Declaration, DeclarationFragments SubHeading) {
180   return addTopLevelRecord(ObjCProtocols, Name, USR, Loc, Availability, Comment,
181                            Declaration, SubHeading);
182 }
183 
184 MacroDefinitionRecord *
185 APISet::addMacroDefinition(StringRef Name, StringRef USR, PresumedLoc Loc,
186                            DeclarationFragments Declaration,
187                            DeclarationFragments SubHeading) {
188   return addTopLevelRecord(Macros, Name, USR, Loc, Declaration, SubHeading);
189 }
190 
191 TypedefRecord *APISet::addTypedef(StringRef Name, StringRef USR,
192                                   PresumedLoc Loc,
193                                   const AvailabilityInfo &Availability,
194                                   const DocComment &Comment,
195                                   DeclarationFragments Declaration,
196                                   DeclarationFragments SubHeading,
197                                   SymbolReference UnderlyingType) {
198   return addTopLevelRecord(Typedefs, Name, USR, Loc, Availability, Comment,
199                            Declaration, SubHeading, UnderlyingType);
200 }
201 
202 StringRef APISet::recordUSR(const Decl *D) {
203   SmallString<128> USR;
204   index::generateUSRForDecl(D, USR);
205   return copyString(USR);
206 }
207 
208 StringRef APISet::recordUSRForMacro(StringRef Name, SourceLocation SL,
209                                     const SourceManager &SM) {
210   SmallString<128> USR;
211   index::generateUSRForMacro(Name, SL, SM, USR);
212   return copyString(USR);
213 }
214 
215 StringRef APISet::copyString(StringRef String) {
216   if (String.empty())
217     return {};
218 
219   // No need to allocate memory and copy if the string has already been stored.
220   if (StringAllocator.identifyObject(String.data()))
221     return String;
222 
223   void *Ptr = StringAllocator.Allocate(String.size(), 1);
224   memcpy(Ptr, String.data(), String.size());
225   return StringRef(reinterpret_cast<const char *>(Ptr), String.size());
226 }
227 
228 APIRecord::~APIRecord() {}
229 
230 ObjCContainerRecord::~ObjCContainerRecord() {}
231 
232 void GlobalRecord::anchor() {}
233 void EnumConstantRecord::anchor() {}
234 void EnumRecord::anchor() {}
235 void StructFieldRecord::anchor() {}
236 void StructRecord::anchor() {}
237 void ObjCPropertyRecord::anchor() {}
238 void ObjCInstanceVariableRecord::anchor() {}
239 void ObjCMethodRecord::anchor() {}
240 void ObjCCategoryRecord::anchor() {}
241 void ObjCInterfaceRecord::anchor() {}
242 void ObjCProtocolRecord::anchor() {}
243 void MacroDefinitionRecord::anchor() {}
244 void TypedefRecord::anchor() {}
245