xref: /freebsd/contrib/llvm-project/clang/lib/ExtractAPI/API.cpp (revision 2d7bb03adb43dd605464db3a9634ff33bf74ca5f)
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(DenseMap<StringRef, APIRecord *> &USRLookupTable,
31                              APISet::RecordMap<RecordTy> &RecordMap,
32                              StringRef USR, CtorArgsTy &&...CtorArgs) {
33    auto Result = RecordMap.insert({USR, nullptr});
34  
35    // Create the record if it does not already exist
36    if (Result.second)
37      Result.first->second =
38          std::make_unique<RecordTy>(USR, std::forward<CtorArgsTy>(CtorArgs)...);
39  
40    auto *Record = Result.first->second.get();
41    USRLookupTable.insert({USR, Record});
42    return Record;
43  }
44  
45  } // namespace
46  
47  GlobalVariableRecord *
48  APISet::addGlobalVar(StringRef Name, StringRef USR, PresumedLoc Loc,
49                       AvailabilitySet Availabilities, LinkageInfo Linkage,
50                       const DocComment &Comment, DeclarationFragments Fragments,
51                       DeclarationFragments SubHeading, bool IsFromSystemHeader) {
52    return addTopLevelRecord(USRBasedLookupTable, GlobalVariables, USR, Name, Loc,
53                             std::move(Availabilities), Linkage, Comment,
54                             Fragments, SubHeading, IsFromSystemHeader);
55  }
56  
57  GlobalFunctionRecord *APISet::addGlobalFunction(
58      StringRef Name, StringRef USR, PresumedLoc Loc,
59      AvailabilitySet Availabilities, LinkageInfo Linkage,
60      const DocComment &Comment, DeclarationFragments Fragments,
61      DeclarationFragments SubHeading, FunctionSignature Signature,
62      bool IsFromSystemHeader) {
63    return addTopLevelRecord(USRBasedLookupTable, GlobalFunctions, USR, Name, Loc,
64                             std::move(Availabilities), Linkage, Comment,
65                             Fragments, SubHeading, Signature,
66                             IsFromSystemHeader);
67  }
68  
69  EnumConstantRecord *APISet::addEnumConstant(EnumRecord *Enum, StringRef Name,
70                                              StringRef USR, PresumedLoc Loc,
71                                              AvailabilitySet Availabilities,
72                                              const DocComment &Comment,
73                                              DeclarationFragments Declaration,
74                                              DeclarationFragments SubHeading,
75                                              bool IsFromSystemHeader) {
76    auto Record = std::make_unique<EnumConstantRecord>(
77        USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
78        SubHeading, IsFromSystemHeader);
79    Record->ParentInformation = APIRecord::HierarchyInformation(
80        Enum->USR, Enum->Name, Enum->getKind(), Enum);
81    USRBasedLookupTable.insert({USR, Record.get()});
82    return Enum->Constants.emplace_back(std::move(Record)).get();
83  }
84  
85  EnumRecord *APISet::addEnum(StringRef Name, StringRef USR, PresumedLoc Loc,
86                              AvailabilitySet Availabilities,
87                              const DocComment &Comment,
88                              DeclarationFragments Declaration,
89                              DeclarationFragments SubHeading,
90                              bool IsFromSystemHeader) {
91    return addTopLevelRecord(USRBasedLookupTable, Enums, USR, Name, Loc,
92                             std::move(Availabilities), Comment, Declaration,
93                             SubHeading, IsFromSystemHeader);
94  }
95  
96  StructFieldRecord *APISet::addStructField(StructRecord *Struct, StringRef Name,
97                                            StringRef USR, PresumedLoc Loc,
98                                            AvailabilitySet Availabilities,
99                                            const DocComment &Comment,
100                                            DeclarationFragments Declaration,
101                                            DeclarationFragments SubHeading,
102                                            bool IsFromSystemHeader) {
103    auto Record = std::make_unique<StructFieldRecord>(
104        USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
105        SubHeading, IsFromSystemHeader);
106    Record->ParentInformation = APIRecord::HierarchyInformation(
107        Struct->USR, Struct->Name, Struct->getKind(), Struct);
108    USRBasedLookupTable.insert({USR, Record.get()});
109    return Struct->Fields.emplace_back(std::move(Record)).get();
110  }
111  
112  StructRecord *APISet::addStruct(StringRef Name, StringRef USR, PresumedLoc Loc,
113                                  AvailabilitySet Availabilities,
114                                  const DocComment &Comment,
115                                  DeclarationFragments Declaration,
116                                  DeclarationFragments SubHeading,
117                                  bool IsFromSystemHeader) {
118    return addTopLevelRecord(USRBasedLookupTable, Structs, USR, Name, Loc,
119                             std::move(Availabilities), Comment, Declaration,
120                             SubHeading, IsFromSystemHeader);
121  }
122  
123  ObjCCategoryRecord *APISet::addObjCCategory(
124      StringRef Name, StringRef USR, PresumedLoc Loc,
125      AvailabilitySet Availabilities, const DocComment &Comment,
126      DeclarationFragments Declaration, DeclarationFragments SubHeading,
127      SymbolReference Interface, bool IsFromSystemHeader) {
128    // Create the category record.
129    auto *Record =
130        addTopLevelRecord(USRBasedLookupTable, ObjCCategories, USR, Name, Loc,
131                          std::move(Availabilities), Comment, Declaration,
132                          SubHeading, Interface, IsFromSystemHeader);
133  
134    // If this category is extending a known interface, associate it with the
135    // ObjCInterfaceRecord.
136    auto It = ObjCInterfaces.find(Interface.USR);
137    if (It != ObjCInterfaces.end())
138      It->second->Categories.push_back(Record);
139  
140    return Record;
141  }
142  
143  ObjCInterfaceRecord *
144  APISet::addObjCInterface(StringRef Name, StringRef USR, PresumedLoc Loc,
145                           AvailabilitySet Availabilities, LinkageInfo Linkage,
146                           const DocComment &Comment,
147                           DeclarationFragments Declaration,
148                           DeclarationFragments SubHeading,
149                           SymbolReference SuperClass, bool IsFromSystemHeader) {
150    return addTopLevelRecord(USRBasedLookupTable, ObjCInterfaces, USR, Name, Loc,
151                             std::move(Availabilities), Linkage, Comment,
152                             Declaration, SubHeading, SuperClass,
153                             IsFromSystemHeader);
154  }
155  
156  ObjCMethodRecord *APISet::addObjCMethod(
157      ObjCContainerRecord *Container, StringRef Name, StringRef USR,
158      PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment,
159      DeclarationFragments Declaration, DeclarationFragments SubHeading,
160      FunctionSignature Signature, bool IsInstanceMethod,
161      bool IsFromSystemHeader) {
162    std::unique_ptr<ObjCMethodRecord> Record;
163    if (IsInstanceMethod)
164      Record = std::make_unique<ObjCInstanceMethodRecord>(
165          USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
166          SubHeading, Signature, IsFromSystemHeader);
167    else
168      Record = std::make_unique<ObjCClassMethodRecord>(
169          USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
170          SubHeading, Signature, IsFromSystemHeader);
171  
172    Record->ParentInformation = APIRecord::HierarchyInformation(
173        Container->USR, Container->Name, Container->getKind(), Container);
174    USRBasedLookupTable.insert({USR, Record.get()});
175    return Container->Methods.emplace_back(std::move(Record)).get();
176  }
177  
178  ObjCPropertyRecord *APISet::addObjCProperty(
179      ObjCContainerRecord *Container, StringRef Name, StringRef USR,
180      PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment,
181      DeclarationFragments Declaration, DeclarationFragments SubHeading,
182      ObjCPropertyRecord::AttributeKind Attributes, StringRef GetterName,
183      StringRef SetterName, bool IsOptional, bool IsInstanceProperty,
184      bool IsFromSystemHeader) {
185    std::unique_ptr<ObjCPropertyRecord> Record;
186    if (IsInstanceProperty)
187      Record = std::make_unique<ObjCInstancePropertyRecord>(
188          USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
189          SubHeading, Attributes, GetterName, SetterName, IsOptional,
190          IsFromSystemHeader);
191    else
192      Record = std::make_unique<ObjCClassPropertyRecord>(
193          USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
194          SubHeading, Attributes, GetterName, SetterName, IsOptional,
195          IsFromSystemHeader);
196    Record->ParentInformation = APIRecord::HierarchyInformation(
197        Container->USR, Container->Name, Container->getKind(), Container);
198    USRBasedLookupTable.insert({USR, Record.get()});
199    return Container->Properties.emplace_back(std::move(Record)).get();
200  }
201  
202  ObjCInstanceVariableRecord *APISet::addObjCInstanceVariable(
203      ObjCContainerRecord *Container, StringRef Name, StringRef USR,
204      PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment,
205      DeclarationFragments Declaration, DeclarationFragments SubHeading,
206      ObjCInstanceVariableRecord::AccessControl Access, bool IsFromSystemHeader) {
207    auto Record = std::make_unique<ObjCInstanceVariableRecord>(
208        USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
209        SubHeading, Access, IsFromSystemHeader);
210    Record->ParentInformation = APIRecord::HierarchyInformation(
211        Container->USR, Container->Name, Container->getKind(), Container);
212    USRBasedLookupTable.insert({USR, Record.get()});
213    return Container->Ivars.emplace_back(std::move(Record)).get();
214  }
215  
216  ObjCProtocolRecord *APISet::addObjCProtocol(StringRef Name, StringRef USR,
217                                              PresumedLoc Loc,
218                                              AvailabilitySet Availabilities,
219                                              const DocComment &Comment,
220                                              DeclarationFragments Declaration,
221                                              DeclarationFragments SubHeading,
222                                              bool IsFromSystemHeader) {
223    return addTopLevelRecord(USRBasedLookupTable, ObjCProtocols, USR, Name, Loc,
224                             std::move(Availabilities), Comment, Declaration,
225                             SubHeading, IsFromSystemHeader);
226  }
227  
228  MacroDefinitionRecord *
229  APISet::addMacroDefinition(StringRef Name, StringRef USR, PresumedLoc Loc,
230                             DeclarationFragments Declaration,
231                             DeclarationFragments SubHeading,
232                             bool IsFromSystemHeader) {
233    return addTopLevelRecord(USRBasedLookupTable, Macros, USR, Name, Loc,
234                             Declaration, SubHeading, IsFromSystemHeader);
235  }
236  
237  TypedefRecord *
238  APISet::addTypedef(StringRef Name, StringRef USR, PresumedLoc Loc,
239                     AvailabilitySet Availabilities, const DocComment &Comment,
240                     DeclarationFragments Declaration,
241                     DeclarationFragments SubHeading,
242                     SymbolReference UnderlyingType, bool IsFromSystemHeader) {
243    return addTopLevelRecord(USRBasedLookupTable, Typedefs, USR, Name, Loc,
244                             std::move(Availabilities), Comment, Declaration,
245                             SubHeading, UnderlyingType, IsFromSystemHeader);
246  }
247  
248  APIRecord *APISet::findRecordForUSR(StringRef USR) const {
249    if (USR.empty())
250      return nullptr;
251  
252    auto It = USRBasedLookupTable.find(USR);
253    if (It != USRBasedLookupTable.end())
254      return It->second;
255    return nullptr;
256  }
257  
258  StringRef APISet::recordUSR(const Decl *D) {
259    SmallString<128> USR;
260    index::generateUSRForDecl(D, USR);
261    return copyString(USR);
262  }
263  
264  StringRef APISet::recordUSRForMacro(StringRef Name, SourceLocation SL,
265                                      const SourceManager &SM) {
266    SmallString<128> USR;
267    index::generateUSRForMacro(Name, SL, SM, USR);
268    return copyString(USR);
269  }
270  
271  StringRef APISet::copyString(StringRef String) {
272    if (String.empty())
273      return {};
274  
275    // No need to allocate memory and copy if the string has already been stored.
276    if (StringAllocator.identifyObject(String.data()))
277      return String;
278  
279    void *Ptr = StringAllocator.Allocate(String.size(), 1);
280    memcpy(Ptr, String.data(), String.size());
281    return StringRef(reinterpret_cast<const char *>(Ptr), String.size());
282  }
283  
284  APIRecord::~APIRecord() {}
285  ObjCContainerRecord::~ObjCContainerRecord() {}
286  ObjCMethodRecord::~ObjCMethodRecord() {}
287  ObjCPropertyRecord::~ObjCPropertyRecord() {}
288  
289  void GlobalFunctionRecord::anchor() {}
290  void GlobalVariableRecord::anchor() {}
291  void EnumConstantRecord::anchor() {}
292  void EnumRecord::anchor() {}
293  void StructFieldRecord::anchor() {}
294  void StructRecord::anchor() {}
295  void ObjCInstancePropertyRecord::anchor() {}
296  void ObjCClassPropertyRecord::anchor() {}
297  void ObjCInstanceVariableRecord::anchor() {}
298  void ObjCInstanceMethodRecord::anchor() {}
299  void ObjCClassMethodRecord::anchor() {}
300  void ObjCCategoryRecord::anchor() {}
301  void ObjCInterfaceRecord::anchor() {}
302  void ObjCProtocolRecord::anchor() {}
303  void MacroDefinitionRecord::anchor() {}
304  void TypedefRecord::anchor() {}
305