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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 190 StringRef APISet::recordUSR(const Decl *D) { 191 SmallString<128> USR; 192 index::generateUSRForDecl(D, USR); 193 return copyString(USR); 194 } 195 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 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 216 APIRecord::~APIRecord() {} 217 218 ObjCContainerRecord::~ObjCContainerRecord() {} 219 220 void GlobalFunctionRecord::anchor() {} 221 void GlobalVariableRecord::anchor() {} 222 void EnumConstantRecord::anchor() {} 223 void EnumRecord::anchor() {} 224 void StructFieldRecord::anchor() {} 225 void StructRecord::anchor() {} 226 void ObjCPropertyRecord::anchor() {} 227 void ObjCInstanceVariableRecord::anchor() {} 228 void ObjCMethodRecord::anchor() {} 229 void ObjCCategoryRecord::anchor() {} 230 void ObjCInterfaceRecord::anchor() {} 231 void ObjCProtocolRecord::anchor() {} 232 void MacroDefinitionRecord::anchor() {} 233 void TypedefRecord::anchor() {} 234