181ad6265SDimitry Andric //===- ExtractAPI/API.cpp ---------------------------------------*- C++ -*-===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric /// 981ad6265SDimitry Andric /// \file 1081ad6265SDimitry Andric /// This file implements the APIRecord and derived record structs, 1181ad6265SDimitry Andric /// and the APISet class. 1281ad6265SDimitry Andric /// 1381ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1481ad6265SDimitry Andric 1581ad6265SDimitry Andric #include "clang/ExtractAPI/API.h" 1681ad6265SDimitry Andric #include "clang/AST/CommentCommandTraits.h" 1781ad6265SDimitry Andric #include "clang/AST/CommentLexer.h" 1881ad6265SDimitry Andric #include "clang/AST/RawCommentList.h" 1981ad6265SDimitry Andric #include "clang/Index/USRGeneration.h" 2081ad6265SDimitry Andric #include "llvm/ADT/STLFunctionalExtras.h" 2181ad6265SDimitry Andric #include "llvm/ADT/StringRef.h" 2281ad6265SDimitry Andric #include <memory> 2381ad6265SDimitry Andric 2481ad6265SDimitry Andric using namespace clang::extractapi; 2581ad6265SDimitry Andric using namespace llvm; 2681ad6265SDimitry Andric 2781ad6265SDimitry Andric namespace { 2881ad6265SDimitry Andric 2981ad6265SDimitry Andric template <typename RecordTy, typename... CtorArgsTy> 30bdd1243dSDimitry Andric RecordTy *addTopLevelRecord(DenseMap<StringRef, APIRecord *> &USRLookupTable, 31bdd1243dSDimitry Andric APISet::RecordMap<RecordTy> &RecordMap, 3281ad6265SDimitry Andric StringRef USR, CtorArgsTy &&...CtorArgs) { 3381ad6265SDimitry Andric auto Result = RecordMap.insert({USR, nullptr}); 3481ad6265SDimitry Andric 3581ad6265SDimitry Andric // Create the record if it does not already exist 3681ad6265SDimitry Andric if (Result.second) 3781ad6265SDimitry Andric Result.first->second = 3881ad6265SDimitry Andric std::make_unique<RecordTy>(USR, std::forward<CtorArgsTy>(CtorArgs)...); 3981ad6265SDimitry Andric 40bdd1243dSDimitry Andric auto *Record = Result.first->second.get(); 41bdd1243dSDimitry Andric USRLookupTable.insert({USR, Record}); 42bdd1243dSDimitry Andric return Record; 4381ad6265SDimitry Andric } 4481ad6265SDimitry Andric 4581ad6265SDimitry Andric } // namespace 4681ad6265SDimitry Andric 4781ad6265SDimitry Andric GlobalVariableRecord * 4881ad6265SDimitry Andric APISet::addGlobalVar(StringRef Name, StringRef USR, PresumedLoc Loc, 49bdd1243dSDimitry Andric AvailabilitySet Availabilities, LinkageInfo Linkage, 5081ad6265SDimitry Andric const DocComment &Comment, DeclarationFragments Fragments, 51bdd1243dSDimitry Andric DeclarationFragments SubHeading, bool IsFromSystemHeader) { 52bdd1243dSDimitry Andric return addTopLevelRecord(USRBasedLookupTable, GlobalVariables, USR, Name, Loc, 53bdd1243dSDimitry Andric std::move(Availabilities), Linkage, Comment, 54bdd1243dSDimitry Andric Fragments, SubHeading, IsFromSystemHeader); 5581ad6265SDimitry Andric } 5681ad6265SDimitry Andric 5781ad6265SDimitry Andric GlobalFunctionRecord *APISet::addGlobalFunction( 5881ad6265SDimitry Andric StringRef Name, StringRef USR, PresumedLoc Loc, 59bdd1243dSDimitry Andric AvailabilitySet Availabilities, LinkageInfo Linkage, 6081ad6265SDimitry Andric const DocComment &Comment, DeclarationFragments Fragments, 61bdd1243dSDimitry Andric DeclarationFragments SubHeading, FunctionSignature Signature, 62bdd1243dSDimitry Andric bool IsFromSystemHeader) { 63bdd1243dSDimitry Andric return addTopLevelRecord(USRBasedLookupTable, GlobalFunctions, USR, Name, Loc, 64bdd1243dSDimitry Andric std::move(Availabilities), Linkage, Comment, 65bdd1243dSDimitry Andric Fragments, SubHeading, Signature, 66bdd1243dSDimitry Andric IsFromSystemHeader); 6781ad6265SDimitry Andric } 6881ad6265SDimitry Andric 69bdd1243dSDimitry Andric EnumConstantRecord *APISet::addEnumConstant(EnumRecord *Enum, StringRef Name, 70bdd1243dSDimitry Andric StringRef USR, PresumedLoc Loc, 71bdd1243dSDimitry Andric AvailabilitySet Availabilities, 72bdd1243dSDimitry Andric const DocComment &Comment, 73bdd1243dSDimitry Andric DeclarationFragments Declaration, 74bdd1243dSDimitry Andric DeclarationFragments SubHeading, 75bdd1243dSDimitry Andric bool IsFromSystemHeader) { 7681ad6265SDimitry Andric auto Record = std::make_unique<EnumConstantRecord>( 77bdd1243dSDimitry Andric USR, Name, Loc, std::move(Availabilities), Comment, Declaration, 78bdd1243dSDimitry Andric SubHeading, IsFromSystemHeader); 79bdd1243dSDimitry Andric Record->ParentInformation = APIRecord::HierarchyInformation( 80bdd1243dSDimitry Andric Enum->USR, Enum->Name, Enum->getKind(), Enum); 81bdd1243dSDimitry Andric USRBasedLookupTable.insert({USR, Record.get()}); 8281ad6265SDimitry Andric return Enum->Constants.emplace_back(std::move(Record)).get(); 8381ad6265SDimitry Andric } 8481ad6265SDimitry Andric 8581ad6265SDimitry Andric EnumRecord *APISet::addEnum(StringRef Name, StringRef USR, PresumedLoc Loc, 86bdd1243dSDimitry Andric AvailabilitySet Availabilities, 8781ad6265SDimitry Andric const DocComment &Comment, 8881ad6265SDimitry Andric DeclarationFragments Declaration, 89bdd1243dSDimitry Andric DeclarationFragments SubHeading, 90bdd1243dSDimitry Andric bool IsFromSystemHeader) { 91bdd1243dSDimitry Andric return addTopLevelRecord(USRBasedLookupTable, Enums, USR, Name, Loc, 92bdd1243dSDimitry Andric std::move(Availabilities), Comment, Declaration, 93bdd1243dSDimitry Andric SubHeading, IsFromSystemHeader); 9481ad6265SDimitry Andric } 9581ad6265SDimitry Andric 9681ad6265SDimitry Andric StructFieldRecord *APISet::addStructField(StructRecord *Struct, StringRef Name, 9781ad6265SDimitry Andric StringRef USR, PresumedLoc Loc, 98bdd1243dSDimitry Andric AvailabilitySet Availabilities, 9981ad6265SDimitry Andric const DocComment &Comment, 10081ad6265SDimitry Andric DeclarationFragments Declaration, 101bdd1243dSDimitry Andric DeclarationFragments SubHeading, 102bdd1243dSDimitry Andric bool IsFromSystemHeader) { 10381ad6265SDimitry Andric auto Record = std::make_unique<StructFieldRecord>( 104bdd1243dSDimitry Andric USR, Name, Loc, std::move(Availabilities), Comment, Declaration, 105bdd1243dSDimitry Andric SubHeading, IsFromSystemHeader); 106bdd1243dSDimitry Andric Record->ParentInformation = APIRecord::HierarchyInformation( 107bdd1243dSDimitry Andric Struct->USR, Struct->Name, Struct->getKind(), Struct); 108bdd1243dSDimitry Andric USRBasedLookupTable.insert({USR, Record.get()}); 10981ad6265SDimitry Andric return Struct->Fields.emplace_back(std::move(Record)).get(); 11081ad6265SDimitry Andric } 11181ad6265SDimitry Andric 11281ad6265SDimitry Andric StructRecord *APISet::addStruct(StringRef Name, StringRef USR, PresumedLoc Loc, 113bdd1243dSDimitry Andric AvailabilitySet Availabilities, 11481ad6265SDimitry Andric const DocComment &Comment, 11581ad6265SDimitry Andric DeclarationFragments Declaration, 116bdd1243dSDimitry Andric DeclarationFragments SubHeading, 117bdd1243dSDimitry Andric bool IsFromSystemHeader) { 118bdd1243dSDimitry Andric return addTopLevelRecord(USRBasedLookupTable, Structs, USR, Name, Loc, 119bdd1243dSDimitry Andric std::move(Availabilities), Comment, Declaration, 120bdd1243dSDimitry Andric SubHeading, IsFromSystemHeader); 12181ad6265SDimitry Andric } 12281ad6265SDimitry Andric 12381ad6265SDimitry Andric ObjCCategoryRecord *APISet::addObjCCategory( 12481ad6265SDimitry Andric StringRef Name, StringRef USR, PresumedLoc Loc, 125bdd1243dSDimitry Andric AvailabilitySet Availabilities, const DocComment &Comment, 12681ad6265SDimitry Andric DeclarationFragments Declaration, DeclarationFragments SubHeading, 127bdd1243dSDimitry Andric SymbolReference Interface, bool IsFromSystemHeader) { 12881ad6265SDimitry Andric // Create the category record. 129bdd1243dSDimitry Andric auto *Record = 130bdd1243dSDimitry Andric addTopLevelRecord(USRBasedLookupTable, ObjCCategories, USR, Name, Loc, 131bdd1243dSDimitry Andric std::move(Availabilities), Comment, Declaration, 132bdd1243dSDimitry Andric SubHeading, Interface, IsFromSystemHeader); 13381ad6265SDimitry Andric 13481ad6265SDimitry Andric // If this category is extending a known interface, associate it with the 13581ad6265SDimitry Andric // ObjCInterfaceRecord. 13681ad6265SDimitry Andric auto It = ObjCInterfaces.find(Interface.USR); 13781ad6265SDimitry Andric if (It != ObjCInterfaces.end()) 13881ad6265SDimitry Andric It->second->Categories.push_back(Record); 13981ad6265SDimitry Andric 14081ad6265SDimitry Andric return Record; 14181ad6265SDimitry Andric } 14281ad6265SDimitry Andric 143bdd1243dSDimitry Andric ObjCInterfaceRecord * 144bdd1243dSDimitry Andric APISet::addObjCInterface(StringRef Name, StringRef USR, PresumedLoc Loc, 145bdd1243dSDimitry Andric AvailabilitySet Availabilities, LinkageInfo Linkage, 146bdd1243dSDimitry Andric const DocComment &Comment, 147bdd1243dSDimitry Andric DeclarationFragments Declaration, 148bdd1243dSDimitry Andric DeclarationFragments SubHeading, 149bdd1243dSDimitry Andric SymbolReference SuperClass, bool IsFromSystemHeader) { 150bdd1243dSDimitry Andric return addTopLevelRecord(USRBasedLookupTable, ObjCInterfaces, USR, Name, Loc, 151bdd1243dSDimitry Andric std::move(Availabilities), Linkage, Comment, 152bdd1243dSDimitry Andric Declaration, SubHeading, SuperClass, 153bdd1243dSDimitry Andric IsFromSystemHeader); 15481ad6265SDimitry Andric } 15581ad6265SDimitry Andric 15681ad6265SDimitry Andric ObjCMethodRecord *APISet::addObjCMethod( 15781ad6265SDimitry Andric ObjCContainerRecord *Container, StringRef Name, StringRef USR, 158bdd1243dSDimitry Andric PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment, 159bdd1243dSDimitry Andric DeclarationFragments Declaration, DeclarationFragments SubHeading, 160bdd1243dSDimitry Andric FunctionSignature Signature, bool IsInstanceMethod, 161bdd1243dSDimitry Andric bool IsFromSystemHeader) { 162bdd1243dSDimitry Andric std::unique_ptr<ObjCMethodRecord> Record; 163bdd1243dSDimitry Andric if (IsInstanceMethod) 164bdd1243dSDimitry Andric Record = std::make_unique<ObjCInstanceMethodRecord>( 165bdd1243dSDimitry Andric USR, Name, Loc, std::move(Availabilities), Comment, Declaration, 166bdd1243dSDimitry Andric SubHeading, Signature, IsFromSystemHeader); 167bdd1243dSDimitry Andric else 168bdd1243dSDimitry Andric Record = std::make_unique<ObjCClassMethodRecord>( 169bdd1243dSDimitry Andric USR, Name, Loc, std::move(Availabilities), Comment, Declaration, 170bdd1243dSDimitry Andric SubHeading, Signature, IsFromSystemHeader); 171bdd1243dSDimitry Andric 172bdd1243dSDimitry Andric Record->ParentInformation = APIRecord::HierarchyInformation( 173bdd1243dSDimitry Andric Container->USR, Container->Name, Container->getKind(), Container); 174bdd1243dSDimitry Andric USRBasedLookupTable.insert({USR, Record.get()}); 17581ad6265SDimitry Andric return Container->Methods.emplace_back(std::move(Record)).get(); 17681ad6265SDimitry Andric } 17781ad6265SDimitry Andric 17881ad6265SDimitry Andric ObjCPropertyRecord *APISet::addObjCProperty( 17981ad6265SDimitry Andric ObjCContainerRecord *Container, StringRef Name, StringRef USR, 180bdd1243dSDimitry Andric PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment, 181bdd1243dSDimitry Andric DeclarationFragments Declaration, DeclarationFragments SubHeading, 18281ad6265SDimitry Andric ObjCPropertyRecord::AttributeKind Attributes, StringRef GetterName, 183bdd1243dSDimitry Andric StringRef SetterName, bool IsOptional, bool IsInstanceProperty, 184bdd1243dSDimitry Andric bool IsFromSystemHeader) { 185bdd1243dSDimitry Andric std::unique_ptr<ObjCPropertyRecord> Record; 186bdd1243dSDimitry Andric if (IsInstanceProperty) 187bdd1243dSDimitry Andric Record = std::make_unique<ObjCInstancePropertyRecord>( 188bdd1243dSDimitry Andric USR, Name, Loc, std::move(Availabilities), Comment, Declaration, 189bdd1243dSDimitry Andric SubHeading, Attributes, GetterName, SetterName, IsOptional, 190bdd1243dSDimitry Andric IsFromSystemHeader); 191bdd1243dSDimitry Andric else 192bdd1243dSDimitry Andric Record = std::make_unique<ObjCClassPropertyRecord>( 193bdd1243dSDimitry Andric USR, Name, Loc, std::move(Availabilities), Comment, Declaration, 194bdd1243dSDimitry Andric SubHeading, Attributes, GetterName, SetterName, IsOptional, 195bdd1243dSDimitry Andric IsFromSystemHeader); 196bdd1243dSDimitry Andric Record->ParentInformation = APIRecord::HierarchyInformation( 197bdd1243dSDimitry Andric Container->USR, Container->Name, Container->getKind(), Container); 198bdd1243dSDimitry Andric USRBasedLookupTable.insert({USR, Record.get()}); 19981ad6265SDimitry Andric return Container->Properties.emplace_back(std::move(Record)).get(); 20081ad6265SDimitry Andric } 20181ad6265SDimitry Andric 20281ad6265SDimitry Andric ObjCInstanceVariableRecord *APISet::addObjCInstanceVariable( 20381ad6265SDimitry Andric ObjCContainerRecord *Container, StringRef Name, StringRef USR, 204bdd1243dSDimitry Andric PresumedLoc Loc, AvailabilitySet Availabilities, const DocComment &Comment, 205bdd1243dSDimitry Andric DeclarationFragments Declaration, DeclarationFragments SubHeading, 206bdd1243dSDimitry Andric ObjCInstanceVariableRecord::AccessControl Access, bool IsFromSystemHeader) { 20781ad6265SDimitry Andric auto Record = std::make_unique<ObjCInstanceVariableRecord>( 208bdd1243dSDimitry Andric USR, Name, Loc, std::move(Availabilities), Comment, Declaration, 209bdd1243dSDimitry Andric SubHeading, Access, IsFromSystemHeader); 210bdd1243dSDimitry Andric Record->ParentInformation = APIRecord::HierarchyInformation( 211bdd1243dSDimitry Andric Container->USR, Container->Name, Container->getKind(), Container); 212bdd1243dSDimitry Andric USRBasedLookupTable.insert({USR, Record.get()}); 21381ad6265SDimitry Andric return Container->Ivars.emplace_back(std::move(Record)).get(); 21481ad6265SDimitry Andric } 21581ad6265SDimitry Andric 216bdd1243dSDimitry Andric ObjCProtocolRecord *APISet::addObjCProtocol(StringRef Name, StringRef USR, 217bdd1243dSDimitry Andric PresumedLoc Loc, 218bdd1243dSDimitry Andric AvailabilitySet Availabilities, 219bdd1243dSDimitry Andric const DocComment &Comment, 220bdd1243dSDimitry Andric DeclarationFragments Declaration, 221bdd1243dSDimitry Andric DeclarationFragments SubHeading, 222bdd1243dSDimitry Andric bool IsFromSystemHeader) { 223bdd1243dSDimitry Andric return addTopLevelRecord(USRBasedLookupTable, ObjCProtocols, USR, Name, Loc, 224bdd1243dSDimitry Andric std::move(Availabilities), Comment, Declaration, 225bdd1243dSDimitry Andric SubHeading, IsFromSystemHeader); 22681ad6265SDimitry Andric } 22781ad6265SDimitry Andric 22881ad6265SDimitry Andric MacroDefinitionRecord * 22981ad6265SDimitry Andric APISet::addMacroDefinition(StringRef Name, StringRef USR, PresumedLoc Loc, 23081ad6265SDimitry Andric DeclarationFragments Declaration, 231bdd1243dSDimitry Andric DeclarationFragments SubHeading, 232bdd1243dSDimitry Andric bool IsFromSystemHeader) { 233bdd1243dSDimitry Andric return addTopLevelRecord(USRBasedLookupTable, Macros, USR, Name, Loc, 234bdd1243dSDimitry Andric Declaration, SubHeading, IsFromSystemHeader); 23581ad6265SDimitry Andric } 23681ad6265SDimitry Andric 237bdd1243dSDimitry Andric TypedefRecord * 238bdd1243dSDimitry Andric APISet::addTypedef(StringRef Name, StringRef USR, PresumedLoc Loc, 239bdd1243dSDimitry Andric AvailabilitySet Availabilities, const DocComment &Comment, 24081ad6265SDimitry Andric DeclarationFragments Declaration, 24181ad6265SDimitry Andric DeclarationFragments SubHeading, 242bdd1243dSDimitry Andric SymbolReference UnderlyingType, bool IsFromSystemHeader) { 243bdd1243dSDimitry Andric return addTopLevelRecord(USRBasedLookupTable, Typedefs, USR, Name, Loc, 244bdd1243dSDimitry Andric std::move(Availabilities), Comment, Declaration, 245bdd1243dSDimitry Andric SubHeading, UnderlyingType, IsFromSystemHeader); 246bdd1243dSDimitry Andric } 247bdd1243dSDimitry Andric 248bdd1243dSDimitry Andric APIRecord *APISet::findRecordForUSR(StringRef USR) const { 249bdd1243dSDimitry Andric if (USR.empty()) 250bdd1243dSDimitry Andric return nullptr; 251bdd1243dSDimitry Andric 252*fe013be4SDimitry Andric return USRBasedLookupTable.lookup(USR); 25381ad6265SDimitry Andric } 25481ad6265SDimitry Andric 25581ad6265SDimitry Andric StringRef APISet::recordUSR(const Decl *D) { 25681ad6265SDimitry Andric SmallString<128> USR; 25781ad6265SDimitry Andric index::generateUSRForDecl(D, USR); 25881ad6265SDimitry Andric return copyString(USR); 25981ad6265SDimitry Andric } 26081ad6265SDimitry Andric 26181ad6265SDimitry Andric StringRef APISet::recordUSRForMacro(StringRef Name, SourceLocation SL, 26281ad6265SDimitry Andric const SourceManager &SM) { 26381ad6265SDimitry Andric SmallString<128> USR; 26481ad6265SDimitry Andric index::generateUSRForMacro(Name, SL, SM, USR); 26581ad6265SDimitry Andric return copyString(USR); 26681ad6265SDimitry Andric } 26781ad6265SDimitry Andric 26881ad6265SDimitry Andric StringRef APISet::copyString(StringRef String) { 26981ad6265SDimitry Andric if (String.empty()) 27081ad6265SDimitry Andric return {}; 27181ad6265SDimitry Andric 27281ad6265SDimitry Andric // No need to allocate memory and copy if the string has already been stored. 27381ad6265SDimitry Andric if (StringAllocator.identifyObject(String.data())) 27481ad6265SDimitry Andric return String; 27581ad6265SDimitry Andric 27681ad6265SDimitry Andric void *Ptr = StringAllocator.Allocate(String.size(), 1); 27781ad6265SDimitry Andric memcpy(Ptr, String.data(), String.size()); 27881ad6265SDimitry Andric return StringRef(reinterpret_cast<const char *>(Ptr), String.size()); 27981ad6265SDimitry Andric } 28081ad6265SDimitry Andric 28181ad6265SDimitry Andric APIRecord::~APIRecord() {} 28281ad6265SDimitry Andric ObjCContainerRecord::~ObjCContainerRecord() {} 283bdd1243dSDimitry Andric ObjCMethodRecord::~ObjCMethodRecord() {} 284bdd1243dSDimitry Andric ObjCPropertyRecord::~ObjCPropertyRecord() {} 28581ad6265SDimitry Andric 28681ad6265SDimitry Andric void GlobalFunctionRecord::anchor() {} 28781ad6265SDimitry Andric void GlobalVariableRecord::anchor() {} 28881ad6265SDimitry Andric void EnumConstantRecord::anchor() {} 28981ad6265SDimitry Andric void EnumRecord::anchor() {} 29081ad6265SDimitry Andric void StructFieldRecord::anchor() {} 29181ad6265SDimitry Andric void StructRecord::anchor() {} 292bdd1243dSDimitry Andric void ObjCInstancePropertyRecord::anchor() {} 293bdd1243dSDimitry Andric void ObjCClassPropertyRecord::anchor() {} 29481ad6265SDimitry Andric void ObjCInstanceVariableRecord::anchor() {} 295bdd1243dSDimitry Andric void ObjCInstanceMethodRecord::anchor() {} 296bdd1243dSDimitry Andric void ObjCClassMethodRecord::anchor() {} 29781ad6265SDimitry Andric void ObjCCategoryRecord::anchor() {} 29881ad6265SDimitry Andric void ObjCInterfaceRecord::anchor() {} 29981ad6265SDimitry Andric void ObjCProtocolRecord::anchor() {} 30081ad6265SDimitry Andric void MacroDefinitionRecord::anchor() {} 30181ad6265SDimitry Andric void TypedefRecord::anchor() {} 302