From 8b76b44e46ac5b4efbf8cb3702f09d353af2a112 Mon Sep 17 00:00:00 2001 From: Erick Velez Date: Thu, 1 Jun 2023 10:22:19 -0700 Subject: [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 --- .../Serialization/SymbolGraphSerializer.cpp | 101 ++++++++++++++++++++- 1 file changed, 96 insertions(+), 5 deletions(-) (limited to 'clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp') diff --git a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp index 534e928..c9fbf0d 100644 --- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp +++ b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp @@ -38,6 +38,14 @@ void serializeObject(Object &Paren, StringRef Key, std::optional 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 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) { @@ -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())); } +template +std::optional 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 +std::optional serializeAccessMixinImpl(const RecordTy &Record, + std::false_type) { + return std::nullopt; +} + +template +void serializeAccessMixin(Object &Paren, const RecordTy &Record) { + auto accessLevel = serializeAccessMixinImpl(Record, has_access()); + 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 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(Record)); break; + case APIRecord::RK_StaticField: + visitStaticFieldRecord(*cast(Record)); + break; + case APIRecord::RK_CXXClass: + visitCXXClassRecord(*cast(Record)); + break; case APIRecord::RK_ObjCInterface: visitObjCContainerRecord(*cast(Record)); break; -- cgit v1.1