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/RawCommentList.h"
17 #include "clang/Index/USRGeneration.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/Support/ErrorHandling.h"
20 #include <memory>
21
22 using namespace clang::extractapi;
23 using namespace llvm;
24
SymbolReference(const APIRecord * R)25 SymbolReference::SymbolReference(const APIRecord *R)
26 : Name(R->Name), USR(R->USR), Record(R) {}
27
castFromRecordContext(const RecordContext * Ctx)28 APIRecord *APIRecord::castFromRecordContext(const RecordContext *Ctx) {
29 switch (Ctx->getKind()) {
30 #define RECORD_CONTEXT(CLASS, KIND) \
31 case KIND: \
32 return static_cast<CLASS *>(const_cast<RecordContext *>(Ctx));
33 #include "clang/ExtractAPI/APIRecords.inc"
34 default:
35 return nullptr;
36 // llvm_unreachable("RecordContext derived class isn't propertly
37 // implemented");
38 }
39 }
40
castToRecordContext(const APIRecord * Record)41 RecordContext *APIRecord::castToRecordContext(const APIRecord *Record) {
42 if (!Record)
43 return nullptr;
44 switch (Record->getKind()) {
45 #define RECORD_CONTEXT(CLASS, KIND) \
46 case KIND: \
47 return static_cast<CLASS *>(const_cast<APIRecord *>(Record));
48 #include "clang/ExtractAPI/APIRecords.inc"
49 default:
50 return nullptr;
51 // llvm_unreachable("RecordContext derived class isn't propertly
52 // implemented");
53 }
54 }
55
IsWellFormed() const56 bool RecordContext::IsWellFormed() const {
57 // Check that First and Last are both null or both non-null.
58 return (First == nullptr) == (Last == nullptr);
59 }
60
stealRecordChain(RecordContext & Other)61 void RecordContext::stealRecordChain(RecordContext &Other) {
62 assert(IsWellFormed());
63 // If we don't have an empty chain append Other's chain into ours.
64 if (First)
65 Last->NextInContext = Other.First;
66 else
67 First = Other.First;
68
69 Last = Other.Last;
70
71 // Delete Other's chain to ensure we don't accidentally traverse it.
72 Other.First = nullptr;
73 Other.Last = nullptr;
74 }
75
addToRecordChain(APIRecord * Record) const76 void RecordContext::addToRecordChain(APIRecord *Record) const {
77 assert(IsWellFormed());
78 if (!First) {
79 First = Record;
80 Last = Record;
81 return;
82 }
83
84 Last->NextInContext = Record;
85 Last = Record;
86 }
87
findRecordForUSR(StringRef USR) const88 APIRecord *APISet::findRecordForUSR(StringRef USR) const {
89 if (USR.empty())
90 return nullptr;
91
92 auto FindIt = USRBasedLookupTable.find(USR);
93 if (FindIt != USRBasedLookupTable.end())
94 return FindIt->getSecond().get();
95
96 return nullptr;
97 }
98
copyString(StringRef String)99 StringRef APISet::copyString(StringRef String) {
100 if (String.empty())
101 return {};
102
103 // No need to allocate memory and copy if the string has already been stored.
104 if (Allocator.identifyObject(String.data()))
105 return String;
106
107 void *Ptr = Allocator.Allocate(String.size(), 1);
108 memcpy(Ptr, String.data(), String.size());
109 return StringRef(reinterpret_cast<const char *>(Ptr), String.size());
110 }
111
createSymbolReference(StringRef Name,StringRef USR,StringRef Source)112 SymbolReference APISet::createSymbolReference(StringRef Name, StringRef USR,
113 StringRef Source) {
114 return SymbolReference(copyString(Name), copyString(USR), copyString(Source));
115 }
116
~APIRecord()117 APIRecord::~APIRecord() {}
~TagRecord()118 TagRecord::~TagRecord() {}
~RecordRecord()119 RecordRecord::~RecordRecord() {}
~RecordFieldRecord()120 RecordFieldRecord::~RecordFieldRecord() {}
~ObjCContainerRecord()121 ObjCContainerRecord::~ObjCContainerRecord() {}
~ObjCMethodRecord()122 ObjCMethodRecord::~ObjCMethodRecord() {}
~ObjCPropertyRecord()123 ObjCPropertyRecord::~ObjCPropertyRecord() {}
~CXXMethodRecord()124 CXXMethodRecord::~CXXMethodRecord() {}
125
anchor()126 void GlobalFunctionRecord::anchor() {}
anchor()127 void GlobalVariableRecord::anchor() {}
anchor()128 void EnumConstantRecord::anchor() {}
anchor()129 void EnumRecord::anchor() {}
anchor()130 void StructFieldRecord::anchor() {}
anchor()131 void StructRecord::anchor() {}
anchor()132 void UnionFieldRecord::anchor() {}
anchor()133 void UnionRecord::anchor() {}
anchor()134 void CXXFieldRecord::anchor() {}
anchor()135 void CXXClassRecord::anchor() {}
anchor()136 void CXXConstructorRecord::anchor() {}
anchor()137 void CXXDestructorRecord::anchor() {}
anchor()138 void CXXInstanceMethodRecord::anchor() {}
anchor()139 void CXXStaticMethodRecord::anchor() {}
anchor()140 void ObjCInstancePropertyRecord::anchor() {}
anchor()141 void ObjCClassPropertyRecord::anchor() {}
anchor()142 void ObjCInstanceVariableRecord::anchor() {}
anchor()143 void ObjCInstanceMethodRecord::anchor() {}
anchor()144 void ObjCClassMethodRecord::anchor() {}
anchor()145 void ObjCCategoryRecord::anchor() {}
anchor()146 void ObjCInterfaceRecord::anchor() {}
anchor()147 void ObjCProtocolRecord::anchor() {}
anchor()148 void MacroDefinitionRecord::anchor() {}
anchor()149 void TypedefRecord::anchor() {}
150