Skip to content

Commit 71b4c22

Browse files
committed
[clang][extract-api] Add enum support
Add support for enum records - Add `EnumConstantRecord` and `EnumRecord` to store API information for enums - Implement `VisitEnumDecl` in `ExtractAPIVisitor` - Implement serializatin for enum records and `MemberOf` relationship - Add test case for enum records - Few other improvements Depends on D122160 Differential Revision: https://reviews.llvm.org/D121873
1 parent 5a2e56b commit 71b4c22

File tree

8 files changed

+785
-17
lines changed

8 files changed

+785
-17
lines changed

clang/include/clang/ExtractAPI/API.h

Lines changed: 80 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,25 @@
3030
#include "llvm/Support/Casting.h"
3131
#include <memory>
3232

33+
namespace {
34+
35+
/// \brief A custom deleter used for ``std::unique_ptr`` to APIRecords stored
36+
/// in the BumpPtrAllocator.
37+
///
38+
/// \tparam T the exact type of the APIRecord subclass.
39+
template <typename T> struct UniquePtrBumpPtrAllocatorDeleter {
40+
void operator()(T *Instance) { Instance->~T(); }
41+
};
42+
43+
/// A unique pointer to an APIRecord stored in the BumpPtrAllocator.
44+
///
45+
/// \tparam T the exact type of the APIRecord subclass.
46+
template <typename T>
47+
using APIRecordUniquePtr =
48+
std::unique_ptr<T, UniquePtrBumpPtrAllocatorDeleter<T>>;
49+
50+
} // anonymous namespace
51+
3352
namespace clang {
3453
namespace extractapi {
3554

@@ -73,6 +92,8 @@ struct APIRecord {
7392
/// Discriminator for LLVM-style RTTI (dyn_cast<> et al.)
7493
enum RecordKind {
7594
RK_Global,
95+
RK_EnumConstant,
96+
RK_Enum,
7697
};
7798

7899
private:
@@ -125,6 +146,36 @@ struct GlobalRecord : APIRecord {
125146
virtual void anchor();
126147
};
127148

149+
/// This holds information associated with enum constants.
150+
struct EnumConstantRecord : APIRecord {
151+
EnumConstantRecord(StringRef Name, StringRef USR, PresumedLoc Loc,
152+
const AvailabilityInfo &Availability,
153+
const DocComment &Comment,
154+
DeclarationFragments Declaration,
155+
DeclarationFragments SubHeading)
156+
: APIRecord(RK_EnumConstant, Name, USR, Loc, Availability,
157+
LinkageInfo::none(), Comment, Declaration, SubHeading) {}
158+
159+
static bool classof(const APIRecord *Record) {
160+
return Record->getKind() == RK_EnumConstant;
161+
}
162+
};
163+
164+
/// This holds information associated with enums.
165+
struct EnumRecord : APIRecord {
166+
SmallVector<APIRecordUniquePtr<EnumConstantRecord>> Constants;
167+
168+
EnumRecord(StringRef Name, StringRef USR, PresumedLoc Loc,
169+
const AvailabilityInfo &Availability, const DocComment &Comment,
170+
DeclarationFragments Declaration, DeclarationFragments SubHeading)
171+
: APIRecord(RK_Enum, Name, USR, Loc, Availability, LinkageInfo::none(),
172+
Comment, Declaration, SubHeading) {}
173+
174+
static bool classof(const APIRecord *Record) {
175+
return Record->getKind() == RK_Enum;
176+
}
177+
};
178+
128179
/// APISet holds the set of API records collected from given inputs.
129180
class APISet {
130181
public:
@@ -166,35 +217,49 @@ class APISet {
166217
DeclarationFragments SubHeading,
167218
FunctionSignature Signature);
168219

169-
private:
170-
/// \brief A custom deleter used for ``std::unique_ptr`` to APIRecords stored
171-
/// in the BumpPtrAllocator.
220+
/// Create and add an enum constant record into the API set.
172221
///
173-
/// \tparam T the exact type of the APIRecord subclass.
174-
template <typename T> struct UniquePtrBumpPtrAllocatorDeleter {
175-
void operator()(T *Instance) { Instance->~T(); }
176-
};
177-
178-
public:
179-
/// A unique pointer to an APIRecord stored in the BumpPtrAllocator.
222+
/// Note: the caller is responsible for keeping the StringRef \p Name and
223+
/// \p USR alive. APISet::copyString provides a way to copy strings into
224+
/// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method
225+
/// to generate the USR for \c D and keep it alive in APISet.
226+
EnumConstantRecord *addEnumConstant(EnumRecord *Enum, StringRef Name,
227+
StringRef USR, PresumedLoc Loc,
228+
const AvailabilityInfo &Availability,
229+
const DocComment &Comment,
230+
DeclarationFragments Declaration,
231+
DeclarationFragments SubHeading);
232+
233+
/// Create and add an enum record into the API set.
180234
///
181-
/// \tparam T the exact type of the APIRecord subclass.
182-
template <typename T>
183-
using APIRecordUniquePtr =
184-
std::unique_ptr<T, UniquePtrBumpPtrAllocatorDeleter<T>>;
235+
/// Note: the caller is responsible for keeping the StringRef \p Name and
236+
/// \p USR alive. APISet::copyString provides a way to copy strings into
237+
/// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method
238+
/// to generate the USR for \c D and keep it alive in APISet.
239+
EnumRecord *addEnum(StringRef Name, StringRef USR, PresumedLoc Loc,
240+
const AvailabilityInfo &Availability,
241+
const DocComment &Comment,
242+
DeclarationFragments Declaration,
243+
DeclarationFragments SubHeading);
185244

186245
/// A map to store the set of GlobalRecord%s with the declaration name as the
187246
/// key.
188247
using GlobalRecordMap =
189248
llvm::MapVector<StringRef, APIRecordUniquePtr<GlobalRecord>>;
190249

250+
/// A map to store the set of EnumRecord%s with the declaration name as the
251+
/// key.
252+
using EnumRecordMap =
253+
llvm::MapVector<StringRef, APIRecordUniquePtr<EnumRecord>>;
254+
191255
/// Get the target triple for the ExtractAPI invocation.
192256
const llvm::Triple &getTarget() const { return Target; }
193257

194258
/// Get the language options used to parse the APIs.
195259
const LangOptions &getLangOpts() const { return LangOpts; }
196260

197261
const GlobalRecordMap &getGlobals() const { return Globals; }
262+
const EnumRecordMap &getEnums() const { return Enums; }
198263

199264
/// Generate and store the USR of declaration \p D.
200265
///
@@ -219,6 +284,7 @@ class APISet {
219284
const LangOptions LangOpts;
220285

221286
GlobalRecordMap Globals;
287+
EnumRecordMap Enums;
222288
};
223289

224290
} // namespace extractapi

clang/include/clang/ExtractAPI/DeclarationFragments.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,14 @@ class DeclarationFragmentsBuilder {
188188
/// Build DeclarationFragments for a function declaration FunctionDecl.
189189
static DeclarationFragments getFragmentsForFunction(const FunctionDecl *);
190190

191+
/// Build DeclarationFragments for an enum constant declaration
192+
/// EnumConstantDecl.
193+
static DeclarationFragments
194+
getFragmentsForEnumConstant(const EnumConstantDecl *);
195+
196+
/// Build DeclarationFragments for an enum declaration EnumDecl.
197+
static DeclarationFragments getFragmentsForEnum(const EnumDecl *);
198+
191199
/// Build sub-heading fragments for a NamedDecl.
192200
static DeclarationFragments getSubHeading(const NamedDecl *);
193201

clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,17 @@ class SymbolGraphSerializer : public APISerializer {
5656
/// write out the serialized JSON object to \p os.
5757
void serialize(raw_ostream &os) override;
5858

59+
/// The kind of a relationship between two symbols.
60+
enum RelationshipKind {
61+
/// The source symbol is a member of the target symbol.
62+
/// For example enum constants are members of the enum, class/instance
63+
/// methods are members of the class, etc.
64+
MemberOf,
65+
};
66+
67+
/// Get the string representation of the relationship kind.
68+
static StringRef getRelationshipString(RelationshipKind Kind);
69+
5970
private:
6071
/// Synthesize the metadata section of the Symbol Graph format.
6172
///
@@ -86,9 +97,19 @@ class SymbolGraphSerializer : public APISerializer {
8697
/// containing common symbol information of \p Record.
8798
Optional<Object> serializeAPIRecord(const APIRecord &Record) const;
8899

100+
/// Serialize the \p Kind relationship between \p Source and \p Target.
101+
///
102+
/// Record the relationship between the two symbols in
103+
/// SymbolGraphSerializer::Relationships.
104+
void serializeRelationship(RelationshipKind Kind, const APIRecord &Source,
105+
const APIRecord &Target);
106+
89107
/// Serialize a global record.
90108
void serializeGlobalRecord(const GlobalRecord &Record);
91109

110+
/// Serialize an enum record.
111+
void serializeEnumRecord(const EnumRecord &Record);
112+
92113
public:
93114
SymbolGraphSerializer(const APISet &API, StringRef ProductName,
94115
APISerializerOption Options = {})

clang/lib/ExtractAPI/API.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,31 @@ APISet::addFunction(StringRef Name, StringRef USR, PresumedLoc Loc,
5959
Comment, Fragments, SubHeading, Signature);
6060
}
6161

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 =
67+
APIRecordUniquePtr<EnumConstantRecord>(new (Allocator) EnumConstantRecord{
68+
Name, USR, Loc, Availability, Comment, Declaration, SubHeading});
69+
return Enum->Constants.emplace_back(std::move(Record)).get();
70+
}
71+
72+
EnumRecord *APISet::addEnum(StringRef Name, StringRef USR, PresumedLoc Loc,
73+
const AvailabilityInfo &Availability,
74+
const DocComment &Comment,
75+
DeclarationFragments Declaration,
76+
DeclarationFragments SubHeading) {
77+
auto Result = Enums.insert({Name, nullptr});
78+
if (Result.second) {
79+
// Create the record if it does not already exist.
80+
auto Record = APIRecordUniquePtr<EnumRecord>(new (Allocator) EnumRecord{
81+
Name, USR, Loc, Availability, Comment, Declaration, SubHeading});
82+
Result.first->second = std::move(Record);
83+
}
84+
return Result.first->second.get();
85+
}
86+
6287
StringRef APISet::recordUSR(const Decl *D) {
6388
SmallString<128> USR;
6489
index::generateUSRForDecl(D, USR);

clang/lib/ExtractAPI/DeclarationFragments.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,35 @@ DeclarationFragmentsBuilder::getFragmentsForFunction(const FunctionDecl *Func) {
401401
return Fragments;
402402
}
403403

404+
DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForEnumConstant(
405+
const EnumConstantDecl *EnumConstDecl) {
406+
DeclarationFragments Fragments;
407+
return Fragments.append(EnumConstDecl->getName(),
408+
DeclarationFragments::FragmentKind::Identifier);
409+
}
410+
411+
DeclarationFragments
412+
DeclarationFragmentsBuilder::getFragmentsForEnum(const EnumDecl *EnumDecl) {
413+
// TODO: After we support typedef records, if there's a typedef for this enum
414+
// just use the declaration fragments of the typedef decl.
415+
416+
DeclarationFragments Fragments, After;
417+
Fragments.append("enum", DeclarationFragments::FragmentKind::Keyword);
418+
419+
if (!EnumDecl->getName().empty())
420+
Fragments.appendSpace().append(
421+
EnumDecl->getName(), DeclarationFragments::FragmentKind::Identifier);
422+
423+
QualType IntegerType = EnumDecl->getIntegerType();
424+
if (!IntegerType.isNull())
425+
Fragments.append(": ", DeclarationFragments::FragmentKind::Text)
426+
.append(
427+
getFragmentsForType(IntegerType, EnumDecl->getASTContext(), After))
428+
.append(std::move(After));
429+
430+
return Fragments;
431+
}
432+
404433
FunctionSignature
405434
DeclarationFragmentsBuilder::getFunctionSignature(const FunctionDecl *Func) {
406435
FunctionSignature Signature;

clang/lib/ExtractAPI/ExtractAPIConsumer.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,40 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
145145
return true;
146146
}
147147

148+
bool VisitEnumDecl(const EnumDecl *Decl) {
149+
if (!Decl->isComplete())
150+
return true;
151+
152+
// Skip forward declaration.
153+
if (!Decl->isThisDeclarationADefinition())
154+
return true;
155+
156+
// Collect symbol information.
157+
StringRef Name = Decl->getName();
158+
StringRef USR = API.recordUSR(Decl);
159+
PresumedLoc Loc =
160+
Context.getSourceManager().getPresumedLoc(Decl->getLocation());
161+
AvailabilityInfo Availability = getAvailability(Decl);
162+
DocComment Comment;
163+
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
164+
Comment = RawComment->getFormattedLines(Context.getSourceManager(),
165+
Context.getDiagnostics());
166+
167+
// Build declaration fragments and sub-heading for the enum.
168+
DeclarationFragments Declaration =
169+
DeclarationFragmentsBuilder::getFragmentsForEnum(Decl);
170+
DeclarationFragments SubHeading =
171+
DeclarationFragmentsBuilder::getSubHeading(Decl);
172+
173+
EnumRecord *EnumRecord = API.addEnum(Name, USR, Loc, Availability, Comment,
174+
Declaration, SubHeading);
175+
176+
// Now collect information about the enumerators in this enum.
177+
recordEnumConstants(EnumRecord, Decl->enumerators());
178+
179+
return true;
180+
}
181+
148182
private:
149183
/// Get availability information of the declaration \p D.
150184
AvailabilityInfo getAvailability(const Decl *D) const {
@@ -177,6 +211,33 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
177211
return Availability;
178212
}
179213

214+
/// Collect API information for the enum constants and associate with the
215+
/// parent enum.
216+
void recordEnumConstants(EnumRecord *EnumRecord,
217+
const EnumDecl::enumerator_range Constants) {
218+
for (const auto *Constant : Constants) {
219+
// Collect symbol information.
220+
StringRef Name = Constant->getName();
221+
StringRef USR = API.recordUSR(Constant);
222+
PresumedLoc Loc =
223+
Context.getSourceManager().getPresumedLoc(Constant->getLocation());
224+
AvailabilityInfo Availability = getAvailability(Constant);
225+
DocComment Comment;
226+
if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant))
227+
Comment = RawComment->getFormattedLines(Context.getSourceManager(),
228+
Context.getDiagnostics());
229+
230+
// Build declaration fragments and sub-heading for the enum constant.
231+
DeclarationFragments Declaration =
232+
DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant);
233+
DeclarationFragments SubHeading =
234+
DeclarationFragmentsBuilder::getSubHeading(Constant);
235+
236+
API.addEnumConstant(EnumRecord, Name, USR, Loc, Availability, Comment,
237+
Declaration, SubHeading);
238+
}
239+
}
240+
180241
ASTContext &Context;
181242
APISet API;
182243
};

0 commit comments

Comments
 (0)