API.cpp 13 KB

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