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 ObjCInterfaceRecord *APISet::addObjCInterface(
113     StringRef Name, StringRef USR, PresumedLoc Loc,
114     const AvailabilityInfo &Availability, LinkageInfo Linkage,
115     const DocComment &Comment, DeclarationFragments Declaration,
116     DeclarationFragments SubHeading, SymbolReference SuperClass) {
117   return addTopLevelRecord(ObjCInterfaces, Name, USR, Loc, Availability,
118                            Linkage, Comment, Declaration, SubHeading,
119                            SuperClass);
120 }
121 
122 ObjCMethodRecord *APISet::addObjCMethod(
123     ObjCContainerRecord *Container, StringRef Name, StringRef USR,
124     PresumedLoc Loc, const AvailabilityInfo &Availability,
125     const DocComment &Comment, DeclarationFragments Declaration,
126     DeclarationFragments SubHeading, FunctionSignature Signature,
127     bool IsInstanceMethod) {
128   auto Record = std::make_unique<ObjCMethodRecord>(
129       Name, USR, Loc, Availability, Comment, Declaration, SubHeading, Signature,
130       IsInstanceMethod);
131   return Container->Methods.emplace_back(std::move(Record)).get();
132 }
133 
134 ObjCPropertyRecord *APISet::addObjCProperty(
135     ObjCContainerRecord *Container, StringRef Name, StringRef USR,
136     PresumedLoc Loc, const AvailabilityInfo &Availability,
137     const DocComment &Comment, DeclarationFragments Declaration,
138     DeclarationFragments SubHeading,
139     ObjCPropertyRecord::AttributeKind Attributes, StringRef GetterName,
140     StringRef SetterName, bool IsOptional) {
141   auto Record = std::make_unique<ObjCPropertyRecord>(
142       Name, USR, Loc, Availability, Comment, Declaration, SubHeading,
143       Attributes, GetterName, SetterName, IsOptional);
144   return Container->Properties.emplace_back(std::move(Record)).get();
145 }
146 
147 ObjCInstanceVariableRecord *APISet::addObjCInstanceVariable(
148     ObjCContainerRecord *Container, StringRef Name, StringRef USR,
149     PresumedLoc Loc, const AvailabilityInfo &Availability,
150     const DocComment &Comment, DeclarationFragments Declaration,
151     DeclarationFragments SubHeading,
152     ObjCInstanceVariableRecord::AccessControl Access) {
153   auto Record = std::make_unique<ObjCInstanceVariableRecord>(
154       Name, USR, Loc, Availability, Comment, Declaration, SubHeading, Access);
155   return Container->Ivars.emplace_back(std::move(Record)).get();
156 }
157 
158 ObjCProtocolRecord *APISet::addObjCProtocol(
159     StringRef Name, StringRef USR, PresumedLoc Loc,
160     const AvailabilityInfo &Availability, const DocComment &Comment,
161     DeclarationFragments Declaration, DeclarationFragments SubHeading) {
162   return addTopLevelRecord(ObjCProtocols, Name, USR, Loc, Availability, Comment,
163                            Declaration, SubHeading);
164 }
165 
166 MacroDefinitionRecord *
167 APISet::addMacroDefinition(StringRef Name, StringRef USR, PresumedLoc Loc,
168                            DeclarationFragments Declaration,
169                            DeclarationFragments SubHeading) {
170   return addTopLevelRecord(Macros, Name, USR, Loc, Declaration, SubHeading);
171 }
172 
173 TypedefRecord *APISet::addTypedef(StringRef Name, StringRef USR,
174                                   PresumedLoc Loc,
175                                   const AvailabilityInfo &Availability,
176                                   const DocComment &Comment,
177                                   DeclarationFragments Declaration,
178                                   DeclarationFragments SubHeading,
179                                   SymbolReference UnderlyingType) {
180   return addTopLevelRecord(Typedefs, Name, USR, Loc, Availability, Comment,
181                            Declaration, SubHeading, UnderlyingType);
182 }
183 
184 StringRef APISet::recordUSR(const Decl *D) {
185   SmallString<128> USR;
186   index::generateUSRForDecl(D, USR);
187   return copyString(USR);
188 }
189 
190 StringRef APISet::recordUSRForMacro(StringRef Name, SourceLocation SL,
191                                     const SourceManager &SM) {
192   SmallString<128> USR;
193   index::generateUSRForMacro(Name, SL, SM, USR);
194   return copyString(USR);
195 }
196 
197 StringRef APISet::copyString(StringRef String) {
198   if (String.empty())
199     return {};
200 
201   // No need to allocate memory and copy if the string has already been stored.
202   if (StringAllocator.identifyObject(String.data()))
203     return String;
204 
205   void *Ptr = StringAllocator.Allocate(String.size(), 1);
206   memcpy(Ptr, String.data(), String.size());
207   return StringRef(reinterpret_cast<const char *>(Ptr), String.size());
208 }
209 
210 APIRecord::~APIRecord() {}
211 
212 ObjCContainerRecord::~ObjCContainerRecord() {}
213 
214 void GlobalRecord::anchor() {}
215 void EnumConstantRecord::anchor() {}
216 void EnumRecord::anchor() {}
217 void StructFieldRecord::anchor() {}
218 void StructRecord::anchor() {}
219 void ObjCPropertyRecord::anchor() {}
220 void ObjCInstanceVariableRecord::anchor() {}
221 void ObjCMethodRecord::anchor() {}
222 void ObjCInterfaceRecord::anchor() {}
223 void ObjCProtocolRecord::anchor() {}
224 void MacroDefinitionRecord::anchor() {}
225 void TypedefRecord::anchor() {}
226