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>
addTopLevelRecord(APISet::RecordMap<RecordTy> & RecordMap,StringRef USR,CtorArgsTy &&...CtorArgs)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 *
addGlobalVar(StringRef Name,StringRef USR,PresumedLoc Loc,const AvailabilityInfo & Availability,LinkageInfo Linkage,const DocComment & Comment,DeclarationFragments Fragments,DeclarationFragments SubHeading)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
addGlobalFunction(StringRef Name,StringRef USR,PresumedLoc Loc,const AvailabilityInfo & Availability,LinkageInfo Linkage,const DocComment & Comment,DeclarationFragments Fragments,DeclarationFragments SubHeading,FunctionSignature Signature)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
addEnumConstant(EnumRecord * Enum,StringRef Name,StringRef USR,PresumedLoc Loc,const AvailabilityInfo & Availability,const DocComment & Comment,DeclarationFragments Declaration,DeclarationFragments SubHeading)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
addEnum(StringRef Name,StringRef USR,PresumedLoc Loc,const AvailabilityInfo & Availability,const DocComment & Comment,DeclarationFragments Declaration,DeclarationFragments SubHeading)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
addStructField(StructRecord * Struct,StringRef Name,StringRef USR,PresumedLoc Loc,const AvailabilityInfo & Availability,const DocComment & Comment,DeclarationFragments Declaration,DeclarationFragments SubHeading)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
addStruct(StringRef Name,StringRef USR,PresumedLoc Loc,const AvailabilityInfo & Availability,const DocComment & Comment,DeclarationFragments Declaration,DeclarationFragments SubHeading)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
addObjCCategory(StringRef Name,StringRef USR,PresumedLoc Loc,const AvailabilityInfo & Availability,const DocComment & Comment,DeclarationFragments Declaration,DeclarationFragments SubHeading,SymbolReference Interface)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
addObjCInterface(StringRef Name,StringRef USR,PresumedLoc Loc,const AvailabilityInfo & Availability,LinkageInfo Linkage,const DocComment & Comment,DeclarationFragments Declaration,DeclarationFragments SubHeading,SymbolReference SuperClass)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
addObjCMethod(ObjCContainerRecord * Container,StringRef Name,StringRef USR,PresumedLoc Loc,const AvailabilityInfo & Availability,const DocComment & Comment,DeclarationFragments Declaration,DeclarationFragments SubHeading,FunctionSignature Signature,bool IsInstanceMethod)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
addObjCProperty(ObjCContainerRecord * Container,StringRef Name,StringRef USR,PresumedLoc Loc,const AvailabilityInfo & Availability,const DocComment & Comment,DeclarationFragments Declaration,DeclarationFragments SubHeading,ObjCPropertyRecord::AttributeKind Attributes,StringRef GetterName,StringRef SetterName,bool IsOptional)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
addObjCInstanceVariable(ObjCContainerRecord * Container,StringRef Name,StringRef USR,PresumedLoc Loc,const AvailabilityInfo & Availability,const DocComment & Comment,DeclarationFragments Declaration,DeclarationFragments SubHeading,ObjCInstanceVariableRecord::AccessControl Access)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
addObjCProtocol(StringRef Name,StringRef USR,PresumedLoc Loc,const AvailabilityInfo & Availability,const DocComment & Comment,DeclarationFragments Declaration,DeclarationFragments SubHeading)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 *
addMacroDefinition(StringRef Name,StringRef USR,PresumedLoc Loc,DeclarationFragments Declaration,DeclarationFragments SubHeading)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
addTypedef(StringRef Name,StringRef USR,PresumedLoc Loc,const AvailabilityInfo & Availability,const DocComment & Comment,DeclarationFragments Declaration,DeclarationFragments SubHeading,SymbolReference UnderlyingType)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
recordUSR(const Decl * D)190 StringRef APISet::recordUSR(const Decl *D) {
191 SmallString<128> USR;
192 index::generateUSRForDecl(D, USR);
193 return copyString(USR);
194 }
195
recordUSRForMacro(StringRef Name,SourceLocation SL,const SourceManager & SM)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
copyString(StringRef String)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
~APIRecord()216 APIRecord::~APIRecord() {}
217
~ObjCContainerRecord()218 ObjCContainerRecord::~ObjCContainerRecord() {}
219
anchor()220 void GlobalFunctionRecord::anchor() {}
anchor()221 void GlobalVariableRecord::anchor() {}
anchor()222 void EnumConstantRecord::anchor() {}
anchor()223 void EnumRecord::anchor() {}
anchor()224 void StructFieldRecord::anchor() {}
anchor()225 void StructRecord::anchor() {}
anchor()226 void ObjCPropertyRecord::anchor() {}
anchor()227 void ObjCInstanceVariableRecord::anchor() {}
anchor()228 void ObjCMethodRecord::anchor() {}
anchor()229 void ObjCCategoryRecord::anchor() {}
anchor()230 void ObjCInterfaceRecord::anchor() {}
anchor()231 void ObjCProtocolRecord::anchor() {}
anchor()232 void MacroDefinitionRecord::anchor() {}
anchor()233 void TypedefRecord::anchor() {}
234