xref: /llvm-project/clang/lib/ExtractAPI/API.cpp (revision b9f4afa1674fe6f101b298d4893cde2ab2d16877)
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