189f6b26fSZixu Wang //===- ExtractAPI/API.cpp ---------------------------------------*- C++ -*-===// 289f6b26fSZixu Wang // 389f6b26fSZixu Wang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 489f6b26fSZixu Wang // See https://llvm.org/LICENSE.txt for license information. 589f6b26fSZixu Wang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 689f6b26fSZixu Wang // 789f6b26fSZixu Wang //===----------------------------------------------------------------------===// 889f6b26fSZixu Wang /// 989f6b26fSZixu Wang /// \file 1089f6b26fSZixu Wang /// This file implements the APIRecord and derived record structs, 1189f6b26fSZixu Wang /// and the APISet class. 1289f6b26fSZixu Wang /// 1389f6b26fSZixu Wang //===----------------------------------------------------------------------===// 1489f6b26fSZixu Wang 1589f6b26fSZixu Wang #include "clang/ExtractAPI/API.h" 16529a0570SDaniel Grumberg #include "llvm/ADT/StringRef.h" 17e05c1b46SDaniel Grumberg #include "llvm/Support/ErrorHandling.h" 180ee06c31SDaniel Grumberg #include <memory> 1989f6b26fSZixu Wang 2089f6b26fSZixu Wang using namespace clang::extractapi; 2189f6b26fSZixu Wang using namespace llvm; 2289f6b26fSZixu Wang 23e05c1b46SDaniel Grumberg SymbolReference::SymbolReference(const APIRecord *R) 24e05c1b46SDaniel Grumberg : Name(R->Name), USR(R->USR), Record(R) {} 25529a0570SDaniel Grumberg 26e05c1b46SDaniel Grumberg APIRecord *APIRecord::castFromRecordContext(const RecordContext *Ctx) { 27e05c1b46SDaniel Grumberg switch (Ctx->getKind()) { 28e05c1b46SDaniel Grumberg #define RECORD_CONTEXT(CLASS, KIND) \ 29e05c1b46SDaniel Grumberg case KIND: \ 30e05c1b46SDaniel Grumberg return static_cast<CLASS *>(const_cast<RecordContext *>(Ctx)); 31e05c1b46SDaniel Grumberg #include "clang/ExtractAPI/APIRecords.inc" 32e05c1b46SDaniel Grumberg default: 33e05c1b46SDaniel Grumberg return nullptr; 34e05c1b46SDaniel Grumberg // llvm_unreachable("RecordContext derived class isn't propertly 35e05c1b46SDaniel Grumberg // implemented"); 36e05c1b46SDaniel Grumberg } 37529a0570SDaniel Grumberg } 38529a0570SDaniel Grumberg 39e05c1b46SDaniel Grumberg RecordContext *APIRecord::castToRecordContext(const APIRecord *Record) { 40e05c1b46SDaniel Grumberg if (!Record) 41e05c1b46SDaniel Grumberg return nullptr; 42e05c1b46SDaniel Grumberg switch (Record->getKind()) { 43e05c1b46SDaniel Grumberg #define RECORD_CONTEXT(CLASS, KIND) \ 44e05c1b46SDaniel Grumberg case KIND: \ 45e05c1b46SDaniel Grumberg return static_cast<CLASS *>(const_cast<APIRecord *>(Record)); 46e05c1b46SDaniel Grumberg #include "clang/ExtractAPI/APIRecords.inc" 47e05c1b46SDaniel Grumberg default: 48e05c1b46SDaniel Grumberg return nullptr; 49e05c1b46SDaniel Grumberg // llvm_unreachable("RecordContext derived class isn't propertly 50e05c1b46SDaniel Grumberg // implemented"); 51e05c1b46SDaniel Grumberg } 5208f034f9SErick Velez } 5308f034f9SErick Velez 542bcbe40fSDaniel Grumberg bool RecordContext::IsWellFormed() const { 552bcbe40fSDaniel Grumberg // Check that First and Last are both null or both non-null. 562bcbe40fSDaniel Grumberg return (First == nullptr) == (Last == nullptr); 572bcbe40fSDaniel Grumberg } 582bcbe40fSDaniel Grumberg 592bcbe40fSDaniel Grumberg void RecordContext::stealRecordChain(RecordContext &Other) { 602bcbe40fSDaniel Grumberg assert(IsWellFormed()); 618f4f3df3SDaniel Grumberg // Other's record chain is empty, nothing to do 628f4f3df3SDaniel Grumberg if (Other.First == nullptr && Other.Last == nullptr) 638f4f3df3SDaniel Grumberg return; 648f4f3df3SDaniel Grumberg 652bcbe40fSDaniel Grumberg // If we don't have an empty chain append Other's chain into ours. 662bcbe40fSDaniel Grumberg if (First) 672bcbe40fSDaniel Grumberg Last->NextInContext = Other.First; 682bcbe40fSDaniel Grumberg else 692bcbe40fSDaniel Grumberg First = Other.First; 702bcbe40fSDaniel Grumberg 712bcbe40fSDaniel Grumberg Last = Other.Last; 722bcbe40fSDaniel Grumberg 738f4f3df3SDaniel Grumberg for (auto *StolenRecord = Other.First; StolenRecord != nullptr; 748f4f3df3SDaniel Grumberg StolenRecord = StolenRecord->getNextInContext()) 758f4f3df3SDaniel Grumberg StolenRecord->Parent = SymbolReference(cast<APIRecord>(this)); 768f4f3df3SDaniel Grumberg 772bcbe40fSDaniel Grumberg // Delete Other's chain to ensure we don't accidentally traverse it. 782bcbe40fSDaniel Grumberg Other.First = nullptr; 792bcbe40fSDaniel Grumberg Other.Last = nullptr; 802bcbe40fSDaniel Grumberg } 812bcbe40fSDaniel Grumberg 82e05c1b46SDaniel Grumberg void RecordContext::addToRecordChain(APIRecord *Record) const { 832bcbe40fSDaniel Grumberg assert(IsWellFormed()); 84e05c1b46SDaniel Grumberg if (!First) { 85e05c1b46SDaniel Grumberg First = Record; 86e05c1b46SDaniel Grumberg Last = Record; 87e05c1b46SDaniel Grumberg return; 8889f6b26fSZixu Wang } 8989f6b26fSZixu Wang 90e05c1b46SDaniel Grumberg Last->NextInContext = Record; 91e05c1b46SDaniel Grumberg Last = Record; 927a851921SDaniel Grumberg } 937a851921SDaniel Grumberg 948f4f3df3SDaniel Grumberg void RecordContext::removeFromRecordChain(APIRecord *Record) { 958f4f3df3SDaniel Grumberg APIRecord *Prev = nullptr; 968f4f3df3SDaniel Grumberg for (APIRecord *Curr = First; Curr != Record; Curr = Curr->NextInContext) 978f4f3df3SDaniel Grumberg Prev = Curr; 988f4f3df3SDaniel Grumberg 998f4f3df3SDaniel Grumberg if (Prev) 1008f4f3df3SDaniel Grumberg Prev->NextInContext = Record->NextInContext; 1018f4f3df3SDaniel Grumberg else 1028f4f3df3SDaniel Grumberg First = Record->NextInContext; 1038f4f3df3SDaniel Grumberg 1048f4f3df3SDaniel Grumberg if (Last == Record) 1058f4f3df3SDaniel Grumberg Last = Prev; 1068f4f3df3SDaniel Grumberg 1078f4f3df3SDaniel Grumberg Record->NextInContext = nullptr; 1088f4f3df3SDaniel Grumberg } 1098f4f3df3SDaniel Grumberg 1107a851921SDaniel Grumberg APIRecord *APISet::findRecordForUSR(StringRef USR) const { 1117a851921SDaniel Grumberg if (USR.empty()) 1127a851921SDaniel Grumberg return nullptr; 1137a851921SDaniel Grumberg 114e05c1b46SDaniel Grumberg auto FindIt = USRBasedLookupTable.find(USR); 115e05c1b46SDaniel Grumberg if (FindIt != USRBasedLookupTable.end()) 116e05c1b46SDaniel Grumberg return FindIt->getSecond().get(); 1179fc45ca0SDaniel Grumberg 118e05c1b46SDaniel Grumberg return nullptr; 119529a0570SDaniel Grumberg } 120529a0570SDaniel Grumberg 12189f6b26fSZixu Wang StringRef APISet::copyString(StringRef String) { 12289f6b26fSZixu Wang if (String.empty()) 12389f6b26fSZixu Wang return {}; 12489f6b26fSZixu Wang 12589f6b26fSZixu Wang // No need to allocate memory and copy if the string has already been stored. 126e05c1b46SDaniel Grumberg if (Allocator.identifyObject(String.data())) 12789f6b26fSZixu Wang return String; 12889f6b26fSZixu Wang 129e05c1b46SDaniel Grumberg void *Ptr = Allocator.Allocate(String.size(), 1); 13089f6b26fSZixu Wang memcpy(Ptr, String.data(), String.size()); 13189f6b26fSZixu Wang return StringRef(reinterpret_cast<const char *>(Ptr), String.size()); 13289f6b26fSZixu Wang } 13389f6b26fSZixu Wang 134e05c1b46SDaniel Grumberg SymbolReference APISet::createSymbolReference(StringRef Name, StringRef USR, 135e05c1b46SDaniel Grumberg StringRef Source) { 136e05c1b46SDaniel Grumberg return SymbolReference(copyString(Name), copyString(USR), copyString(Source)); 137e05c1b46SDaniel Grumberg } 138e05c1b46SDaniel Grumberg 1398f4f3df3SDaniel Grumberg void APISet::removeRecord(StringRef USR) { 1408f4f3df3SDaniel Grumberg auto Result = USRBasedLookupTable.find(USR); 1418f4f3df3SDaniel Grumberg if (Result != USRBasedLookupTable.end()) { 1428f4f3df3SDaniel Grumberg auto *Record = Result->getSecond().get(); 1438f4f3df3SDaniel Grumberg auto &ParentReference = Record->Parent; 1448f4f3df3SDaniel Grumberg auto *ParentRecord = const_cast<APIRecord *>(ParentReference.Record); 1458f4f3df3SDaniel Grumberg if (!ParentRecord) 1468f4f3df3SDaniel Grumberg ParentRecord = findRecordForUSR(ParentReference.USR); 1478f4f3df3SDaniel Grumberg 1488f4f3df3SDaniel Grumberg if (auto *ParentCtx = llvm::cast_if_present<RecordContext>(ParentRecord)) { 1498f4f3df3SDaniel Grumberg ParentCtx->removeFromRecordChain(Record); 1508f4f3df3SDaniel Grumberg if (auto *RecordAsCtx = llvm::dyn_cast<RecordContext>(Record)) 1518f4f3df3SDaniel Grumberg ParentCtx->stealRecordChain(*RecordAsCtx); 1528f4f3df3SDaniel Grumberg } else { 153*b9f4afa1SDaniel Grumberg auto *It = llvm::find(TopLevelRecords, Record); 154*b9f4afa1SDaniel Grumberg if (It != TopLevelRecords.end()) 155*b9f4afa1SDaniel Grumberg TopLevelRecords.erase(It); 1568f4f3df3SDaniel Grumberg if (auto *RecordAsCtx = llvm::dyn_cast<RecordContext>(Record)) { 1578f4f3df3SDaniel Grumberg for (const auto *Child = RecordAsCtx->First; Child != nullptr; 1588f4f3df3SDaniel Grumberg Child = Child->getNextInContext()) 159*b9f4afa1SDaniel Grumberg TopLevelRecords.push_back(Child); 1608f4f3df3SDaniel Grumberg } 1618f4f3df3SDaniel Grumberg } 1628f4f3df3SDaniel Grumberg USRBasedLookupTable.erase(Result); 1638f4f3df3SDaniel Grumberg } 1648f4f3df3SDaniel Grumberg } 1658f4f3df3SDaniel Grumberg 1668f4f3df3SDaniel Grumberg void APISet::removeRecord(APIRecord *Record) { removeRecord(Record->USR); } 1678f4f3df3SDaniel Grumberg 16889f6b26fSZixu Wang APIRecord::~APIRecord() {} 1692bcbe40fSDaniel Grumberg TagRecord::~TagRecord() {} 170e05c1b46SDaniel Grumberg RecordRecord::~RecordRecord() {} 171e05c1b46SDaniel Grumberg RecordFieldRecord::~RecordFieldRecord() {} 1729b36e126SZixu Wang ObjCContainerRecord::~ObjCContainerRecord() {} 1737a851921SDaniel Grumberg ObjCMethodRecord::~ObjCMethodRecord() {} 1747a851921SDaniel Grumberg ObjCPropertyRecord::~ObjCPropertyRecord() {} 17575f55eb3SErick Velez CXXMethodRecord::~CXXMethodRecord() {} 1769b36e126SZixu Wang 177236b6a0eSDaniel Grumberg void GlobalFunctionRecord::anchor() {} 178236b6a0eSDaniel Grumberg void GlobalVariableRecord::anchor() {} 179e5a7d272SZixu Wang void EnumConstantRecord::anchor() {} 180e5a7d272SZixu Wang void EnumRecord::anchor() {} 181e05c1b46SDaniel Grumberg void StructFieldRecord::anchor() {} 182e05c1b46SDaniel Grumberg void StructRecord::anchor() {} 183e05c1b46SDaniel Grumberg void UnionFieldRecord::anchor() {} 184e05c1b46SDaniel Grumberg void UnionRecord::anchor() {} 18575f55eb3SErick Velez void CXXFieldRecord::anchor() {} 18675f55eb3SErick Velez void CXXClassRecord::anchor() {} 18775f55eb3SErick Velez void CXXConstructorRecord::anchor() {} 18875f55eb3SErick Velez void CXXDestructorRecord::anchor() {} 18975f55eb3SErick Velez void CXXInstanceMethodRecord::anchor() {} 19075f55eb3SErick Velez void CXXStaticMethodRecord::anchor() {} 1917a851921SDaniel Grumberg void ObjCInstancePropertyRecord::anchor() {} 1927a851921SDaniel Grumberg void ObjCClassPropertyRecord::anchor() {} 1939b36e126SZixu Wang void ObjCInstanceVariableRecord::anchor() {} 1947a851921SDaniel Grumberg void ObjCInstanceMethodRecord::anchor() {} 1957a851921SDaniel Grumberg void ObjCClassMethodRecord::anchor() {} 196178aad9bSZixu Wang void ObjCCategoryRecord::anchor() {} 1979b36e126SZixu Wang void ObjCInterfaceRecord::anchor() {} 198d1d34bafSZixu Wang void ObjCProtocolRecord::anchor() {} 199529a0570SDaniel Grumberg void MacroDefinitionRecord::anchor() {} 2009fc45ca0SDaniel Grumberg void TypedefRecord::anchor() {} 201