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