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 return USRBasedLookupTable.lookup(USR); 253 } 254 255 StringRef APISet::recordUSR(const Decl *D) { 256 SmallString<128> USR; 257 index::generateUSRForDecl(D, USR); 258 return copyString(USR); 259 } 260 261 StringRef APISet::recordUSRForMacro(StringRef Name, SourceLocation SL, 262 const SourceManager &SM) { 263 SmallString<128> USR; 264 index::generateUSRForMacro(Name, SL, SM, USR); 265 return copyString(USR); 266 } 267 268 StringRef APISet::copyString(StringRef String) { 269 if (String.empty()) 270 return {}; 271 272 // No need to allocate memory and copy if the string has already been stored. 273 if (StringAllocator.identifyObject(String.data())) 274 return String; 275 276 void *Ptr = StringAllocator.Allocate(String.size(), 1); 277 memcpy(Ptr, String.data(), String.size()); 278 return StringRef(reinterpret_cast<const char *>(Ptr), String.size()); 279 } 280 281 APIRecord::~APIRecord() {} 282 ObjCContainerRecord::~ObjCContainerRecord() {} 283 ObjCMethodRecord::~ObjCMethodRecord() {} 284 ObjCPropertyRecord::~ObjCPropertyRecord() {} 285 286 void GlobalFunctionRecord::anchor() {} 287 void GlobalVariableRecord::anchor() {} 288 void EnumConstantRecord::anchor() {} 289 void EnumRecord::anchor() {} 290 void StructFieldRecord::anchor() {} 291 void StructRecord::anchor() {} 292 void ObjCInstancePropertyRecord::anchor() {} 293 void ObjCClassPropertyRecord::anchor() {} 294 void ObjCInstanceVariableRecord::anchor() {} 295 void ObjCInstanceMethodRecord::anchor() {} 296 void ObjCClassMethodRecord::anchor() {} 297 void ObjCCategoryRecord::anchor() {} 298 void ObjCInterfaceRecord::anchor() {} 299 void ObjCProtocolRecord::anchor() {} 300 void MacroDefinitionRecord::anchor() {} 301 void TypedefRecord::anchor() {} 302