[clang][ExtractAPI] Add support for C++ classes

Add ExtractAPI support C++ classes, fields,  methods, and various qualifiers and specifiers

Differential Revision: https://reviews.llvm.org/D153557
This commit is contained in:
Erick Velez
2023-06-01 10:22:19 -07:00
parent b711d11c83
commit 8b76b44e46
16 changed files with 3261 additions and 46 deletions

View File

@@ -38,6 +38,14 @@ void serializeObject(Object &Paren, StringRef Key, std::optional<Object> Obj) {
Paren[Key] = std::move(*Obj);
}
/// Helper function to inject a StringRef \p String into an object \p Paren at
/// position \p Key
void serializeString(Object &Paren, StringRef Key,
std::optional<std::string> String) {
if (String)
Paren[Key] = std::move(*String);
}
/// Helper function to inject a JSON array \p Array into object \p Paren at
/// position \p Key.
void serializeArray(Object &Paren, StringRef Key, std::optional<Array> Array) {
@@ -189,9 +197,10 @@ StringRef getLanguageName(Language Lang) {
return "c";
case Language::ObjC:
return "objective-c";
case Language::CXX:
return "c++";
// Unsupported language currently
case Language::CXX:
case Language::ObjCXX:
case Language::OpenCL:
case Language::OpenCLCXX:
@@ -366,6 +375,38 @@ Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
Kind["identifier"] = AddLangPrefix("struct");
Kind["displayName"] = "Structure";
break;
case APIRecord::RK_CXXField:
Kind["identifier"] = AddLangPrefix("property");
Kind["displayName"] = "Instance Property";
break;
case APIRecord::RK_Union:
Kind["identifier"] = AddLangPrefix("union");
Kind["displayName"] = "Union";
break;
case APIRecord::RK_StaticField:
Kind["identifier"] = AddLangPrefix("type.property");
Kind["displayName"] = "Type Property";
break;
case APIRecord::RK_CXXClass:
Kind["identifier"] = AddLangPrefix("class");
Kind["displayName"] = "Class";
break;
case APIRecord::RK_CXXStaticMethod:
Kind["identifier"] = AddLangPrefix("type.method");
Kind["displayName"] = "Static Method";
break;
case APIRecord::RK_CXXInstanceMethod:
Kind["identifier"] = AddLangPrefix("method");
Kind["displayName"] = "Instance Method";
break;
case APIRecord::RK_CXXConstructorMethod:
Kind["identifier"] = AddLangPrefix("method");
Kind["displayName"] = "Constructor";
break;
case APIRecord::RK_CXXDestructorMethod:
Kind["identifier"] = AddLangPrefix("method");
Kind["displayName"] = "Destructor";
break;
case APIRecord::RK_ObjCIvar:
Kind["identifier"] = AddLangPrefix("ivar");
Kind["displayName"] = "Instance Variable";
@@ -470,6 +511,31 @@ void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) {
Record, has_function_signature<RecordTy>()));
}
template <typename RecordTy>
std::optional<std::string> serializeAccessMixinImpl(const RecordTy &Record,
std::true_type) {
const auto &AccessControl = Record.Access;
std::string Access;
if (AccessControl.empty())
return std::nullopt;
Access = AccessControl.getAccess();
return Access;
}
template <typename RecordTy>
std::optional<std::string> serializeAccessMixinImpl(const RecordTy &Record,
std::false_type) {
return std::nullopt;
}
template <typename RecordTy>
void serializeAccessMixin(Object &Paren, const RecordTy &Record) {
auto accessLevel = serializeAccessMixinImpl(Record, has_access<RecordTy>());
if (!accessLevel.has_value())
accessLevel = "public";
serializeString(Paren, "accessLevel", accessLevel);
}
struct PathComponent {
StringRef USR;
StringRef Name;
@@ -543,7 +609,6 @@ Array generateParentContexts(const RecordTy &Record, const APISet &API,
return ParentContexts;
}
} // namespace
/// Defines the format version emitted by SymbolGraphSerializer.
@@ -602,9 +667,6 @@ SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const {
serializeObject(Obj, "docComment", serializeDocComment(Record.Comment));
serializeArray(Obj, "declarationFragments",
serializeDeclarationFragments(Record.Declaration));
// TODO: Once we keep track of symbol access information serialize it
// correctly here.
Obj["accessLevel"] = "public";
SmallVector<StringRef, 4> PathComponentsNames;
// If this returns true it indicates that we couldn't find a symbol in the
// hierarchy.
@@ -617,6 +679,7 @@ SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const {
serializeArray(Obj, "pathComponents", Array(PathComponentsNames));
serializeFunctionSignatureMixin(Obj, Record);
serializeAccessMixin(Obj, Record);
return Obj;
}
@@ -698,6 +761,28 @@ void SymbolGraphSerializer::visitStructRecord(const StructRecord &Record) {
serializeMembers(Record, Record.Fields);
}
void SymbolGraphSerializer::visitStaticFieldRecord(
const StaticFieldRecord &Record) {
auto StaticField = serializeAPIRecord(Record);
if (!StaticField)
return;
Symbols.emplace_back(std::move(*StaticField));
serializeRelationship(RelationshipKind::MemberOf, Record, Record.Context);
}
void SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord &Record) {
auto Class = serializeAPIRecord(Record);
if (!Class)
return;
Symbols.emplace_back(std::move(*Class));
serializeMembers(Record, Record.Fields);
serializeMembers(Record, Record.Methods);
for (const auto Base : Record.Bases)
serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
}
void SymbolGraphSerializer::visitObjCContainerRecord(
const ObjCContainerRecord &Record) {
auto ObjCContainer = serializeAPIRecord(Record);
@@ -761,6 +846,12 @@ void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) {
case APIRecord::RK_Struct:
visitStructRecord(*cast<StructRecord>(Record));
break;
case APIRecord::RK_StaticField:
visitStaticFieldRecord(*cast<StaticFieldRecord>(Record));
break;
case APIRecord::RK_CXXClass:
visitCXXClassRecord(*cast<CXXClassRecord>(Record));
break;
case APIRecord::RK_ObjCInterface:
visitObjCContainerRecord(*cast<ObjCInterfaceRecord>(Record));
break;