evelez7 updated this revision to Diff 533788.
evelez7 added a comment.

Add access control serialization


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D153557/new/

https://reviews.llvm.org/D153557

Files:
  clang/include/clang/ExtractAPI/API.h
  clang/include/clang/ExtractAPI/DeclarationFragments.h
  clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
  clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
  clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
  clang/lib/ExtractAPI/API.cpp
  clang/lib/ExtractAPI/DeclarationFragments.cpp
  clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp

Index: clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
===================================================================
--- clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
+++ clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
@@ -17,6 +17,7 @@
 #include "clang/ExtractAPI/DeclarationFragments.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/STLFunctionalExtras.h"
+#include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/Path.h"
@@ -38,6 +39,14 @@
     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<StringRef> 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) {
@@ -366,6 +375,38 @@
     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 @@
                       Record, has_function_signature<RecordTy>()));
 }
 
+template <typename RecordTy>
+std::optional<StringRef> serializeAccessMixinImpl(const RecordTy &Record,
+                                                  std::true_type) {
+  const auto &AccessControl = Record.Access;
+  StringRef Access;
+  if (AccessControl.empty())
+    return std::nullopt;
+  Access = AccessControl.getAccess();
+  return Access;
+}
+
+template <typename RecordTy>
+std::optional<StringRef> 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 @@
 
   return ParentContexts;
 }
-
 } // namespace
 
 /// Defines the format version emitted by SymbolGraphSerializer.
@@ -602,9 +667,6 @@
   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 @@
   serializeArray(Obj, "pathComponents", Array(PathComponentsNames));
 
   serializeFunctionSignatureMixin(Obj, Record);
+  serializeAccessMixin(Obj, Record);
 
   return Obj;
 }
@@ -698,6 +761,28 @@
   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 @@
   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;
Index: clang/lib/ExtractAPI/DeclarationFragments.cpp
===================================================================
--- clang/lib/ExtractAPI/DeclarationFragments.cpp
+++ clang/lib/ExtractAPI/DeclarationFragments.cpp
@@ -12,8 +12,10 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/ExtractAPI/DeclarationFragments.h"
+#include "clang/AST/DeclCXX.h"
 #include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h"
 #include "clang/Index/USRGeneration.h"
+#include "clang/Parse/Parser.h"
 #include "llvm/ADT/StringSwitch.h"
 
 using namespace clang::extractapi;
@@ -84,6 +86,43 @@
       .Default(DeclarationFragments::FragmentKind::None);
 }
 
+DeclarationFragments DeclarationFragments::getExceptionSpecificationString(
+    ExceptionSpecificationType ExceptionSpec) {
+  DeclarationFragments Fragments;
+  switch (ExceptionSpec) {
+  case ExceptionSpecificationType::EST_BasicNoexcept:
+    Fragments.append(" noexcept", DeclarationFragments::FragmentKind::Keyword);
+    return Fragments;
+  case ExceptionSpecificationType::EST_DynamicNone:
+    Fragments.append(" throw()", DeclarationFragments::FragmentKind::Keyword);
+    return Fragments;
+  case ExceptionSpecificationType::EST_NoexceptFalse:
+    Fragments.append(" noexcept(false)",
+                     DeclarationFragments::FragmentKind::Keyword);
+    return Fragments;
+  case ExceptionSpecificationType::EST_NoexceptTrue:
+    Fragments.append(" noexcept(true)",
+                     DeclarationFragments::FragmentKind::Keyword);
+    return Fragments;
+  case ExceptionSpecificationType::EST_None:
+  default:
+    return Fragments;
+  }
+}
+
+DeclarationFragments
+DeclarationFragments::getStructureTypeFragment(const RecordDecl *Record) {
+  DeclarationFragments Fragments;
+  if (Record->isStruct())
+    Fragments.append("struct", DeclarationFragments::FragmentKind::Keyword);
+  else if (Record->isUnion())
+    Fragments.append("union", DeclarationFragments::FragmentKind::Keyword);
+  else
+    Fragments.append("class", DeclarationFragments::FragmentKind::Keyword);
+
+  return Fragments;
+}
+
 // NNS stores C++ nested name specifiers, which are prefixes to qualified names.
 // Build declaration fragments for NNS recursively so that we have the USR for
 // every part in a qualified name, and also leaves the actual underlying type
@@ -369,6 +408,9 @@
 DeclarationFragments
 DeclarationFragmentsBuilder::getFragmentsForVar(const VarDecl *Var) {
   DeclarationFragments Fragments;
+  if (Var->isConstexpr())
+    Fragments.append("constexpr ", DeclarationFragments::FragmentKind::Keyword);
+
   StorageClass SC = Var->getStorageClass();
   if (SC != SC_None)
     Fragments
@@ -437,7 +479,10 @@
   case SC_Register:
     llvm_unreachable("invalid for functions");
   }
-  // FIXME: Handle C++ function specifiers: constexpr, consteval, explicit, etc.
+  if (Func->isConsteval()) // if consteval, it is also constexpr
+    Fragments.append("consteval ", DeclarationFragments::FragmentKind::Keyword);
+  else if (Func->isConstexpr())
+    Fragments.append("constexpr ", DeclarationFragments::FragmentKind::Keyword);
 
   // FIXME: Is `after` actually needed here?
   DeclarationFragments After;
@@ -456,6 +501,9 @@
   }
   Fragments.append(")", DeclarationFragments::FragmentKind::Text);
 
+  Fragments.append(DeclarationFragments::getExceptionSpecificationString(
+      Func->getExceptionSpecType()));
+
   // FIXME: Handle exception specifiers: throw, noexcept
   return Fragments.append(";", DeclarationFragments::FragmentKind::Text);
 }
@@ -492,7 +540,12 @@
 DeclarationFragments
 DeclarationFragmentsBuilder::getFragmentsForField(const FieldDecl *Field) {
   DeclarationFragments After;
-  return getFragmentsForType(Field->getType(), Field->getASTContext(), After)
+  DeclarationFragments Fragments;
+  if (Field->isMutable())
+    Fragments.append("mutable ", DeclarationFragments::FragmentKind::Keyword);
+  return Fragments
+      .append(
+          getFragmentsForType(Field->getType(), Field->getASTContext(), After))
       .appendSpace()
       .append(Field->getName(), DeclarationFragments::FragmentKind::Identifier)
       .append(std::move(After));
@@ -513,6 +566,77 @@
   return Fragments.append(";", DeclarationFragments::FragmentKind::Text);
 }
 
+DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForCXXClass(
+    const CXXRecordDecl *Record) {
+  if (const auto *TypedefNameDecl = Record->getTypedefNameForAnonDecl())
+    return getFragmentsForTypedef(TypedefNameDecl);
+
+  DeclarationFragments Fragments;
+  Fragments.append(DeclarationFragments::getStructureTypeFragment(Record));
+
+  if (!Record->getName().empty())
+    Fragments.appendSpace().append(
+        Record->getName(), DeclarationFragments::FragmentKind::Identifier);
+
+  return Fragments.append(";", DeclarationFragments::FragmentKind::Text);
+}
+
+DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForCXXMethod(
+    const CXXMethodDecl *Method) {
+  DeclarationFragments Fragments;
+  StringRef Name;
+  if (isa<CXXConstructorDecl>(Method)) {
+    auto Constructor = dyn_cast<CXXConstructorDecl>(Method);
+    Name = cast<CXXRecordDecl>(Constructor->getDeclContext())->getName();
+    if (Constructor->isExplicit())
+      Fragments.append("explicit ",
+                       DeclarationFragments::FragmentKind::Keyword);
+  } else if (isa<CXXDestructorDecl>(Method))
+    // TODO: add '~'
+    Name = cast<CXXRecordDecl>(Method->getDeclContext())->getName();
+  else if (isa<CXXConversionDecl>(Method)) {
+    Name = "Conversion"; // placeholder
+    auto Conversion = dyn_cast<CXXConversionDecl>(Method);
+    if (Conversion->isExplicit())
+      Fragments.append("explicit ",
+                       DeclarationFragments::FragmentKind::Keyword);
+  } else {
+    Name = Method->getName();
+    if (Method->isStatic())
+      Fragments.append("static ", DeclarationFragments::FragmentKind::Keyword);
+    if (Method->isConstexpr())
+      Fragments.append("constexpr ",
+                       DeclarationFragments::FragmentKind::Keyword);
+    if (Method->isVolatile())
+      Fragments.append("volatile ",
+                       DeclarationFragments::FragmentKind::Keyword);
+  }
+
+  // Build return type
+  DeclarationFragments After;
+  Fragments
+      .append(getFragmentsForType(Method->getReturnType(),
+                                  Method->getASTContext(), After))
+      .appendSpace()
+      .append(Name, DeclarationFragments::FragmentKind::Identifier)
+      .append(std::move(After));
+  Fragments.append("(", DeclarationFragments::FragmentKind::Text);
+  for (unsigned i = 0, end = Method->getNumParams(); i != end; ++i) {
+    if (i)
+      Fragments.append(", ", DeclarationFragments::FragmentKind::Text);
+    Fragments.append(getFragmentsForParam(Method->getParamDecl(i)));
+  }
+  Fragments.append(")", DeclarationFragments::FragmentKind::Text);
+
+  if (Method->isConst())
+    Fragments.append(" const", DeclarationFragments::FragmentKind::Keyword);
+
+  Fragments.append(DeclarationFragments::getExceptionSpecificationString(
+      Method->getExceptionSpecType()));
+
+  return Fragments.append(";", DeclarationFragments::FragmentKind::Text);
+}
+
 DeclarationFragments
 DeclarationFragmentsBuilder::getFragmentsForMacro(StringRef Name,
                                                   const MacroDirective *MD) {
@@ -763,24 +887,6 @@
   return Fragments.append(";", DeclarationFragments::FragmentKind::Text);
 }
 
-template <typename FunctionT>
-FunctionSignature
-DeclarationFragmentsBuilder::getFunctionSignature(const FunctionT *Function) {
-  FunctionSignature Signature;
-
-  DeclarationFragments ReturnType, After;
-  ReturnType
-      .append(getFragmentsForType(Function->getReturnType(),
-                                  Function->getASTContext(), After))
-      .append(std::move(After));
-  Signature.setReturnType(ReturnType);
-
-  for (const auto *Param : Function->parameters())
-    Signature.addParameter(Param->getName(), getFragmentsForParam(Param));
-
-  return Signature;
-}
-
 // Instantiate template for FunctionDecl.
 template FunctionSignature
 DeclarationFragmentsBuilder::getFunctionSignature(const FunctionDecl *);
@@ -793,7 +899,10 @@
 DeclarationFragments
 DeclarationFragmentsBuilder::getSubHeading(const NamedDecl *Decl) {
   DeclarationFragments Fragments;
-  if (!Decl->getName().empty())
+  if (isa<CXXConstructorDecl>(Decl) || isa<CXXDestructorDecl>(Decl))
+    Fragments.append(cast<CXXRecordDecl>(Decl->getDeclContext())->getName(),
+                     DeclarationFragments::FragmentKind::Identifier);
+  else if (!Decl->getName().empty())
     Fragments.append(Decl->getName(),
                      DeclarationFragments::FragmentKind::Identifier);
   return Fragments;
Index: clang/lib/ExtractAPI/API.cpp
===================================================================
--- clang/lib/ExtractAPI/API.cpp
+++ clang/lib/ExtractAPI/API.cpp
@@ -16,6 +16,7 @@
 #include "clang/AST/CommentCommandTraits.h"
 #include "clang/AST/CommentLexer.h"
 #include "clang/AST/RawCommentList.h"
+#include "clang/ExtractAPI/DeclarationFragments.h"
 #include "clang/Index/USRGeneration.h"
 #include "llvm/ADT/STLFunctionalExtras.h"
 #include "llvm/ADT/StringRef.h"
@@ -41,7 +42,6 @@
   USRLookupTable.insert({USR, Record});
   return Record;
 }
-
 } // namespace
 
 GlobalVariableRecord *
@@ -120,6 +120,91 @@
                            SubHeading, IsFromSystemHeader);
 }
 
+StaticFieldRecord *
+APISet::addStaticField(StringRef Name, StringRef USR, PresumedLoc Loc,
+                       AvailabilitySet Availabilities, LinkageInfo Linkage,
+                       const DocComment &Comment,
+                       DeclarationFragments Declaration,
+                       DeclarationFragments SubHeading, SymbolReference Context,
+                       AccessControl Access, bool IsFromSystemHeader) {
+  return addTopLevelRecord(USRBasedLookupTable, StaticFields, USR, Name, Loc,
+                           std::move(Availabilities), Linkage, Comment,
+                           Declaration, SubHeading, Context, Access,
+                           IsFromSystemHeader);
+}
+
+CXXFieldRecord *
+APISet::addCXXField(CXXClassRecord *CXXClass, StringRef Name, StringRef USR,
+                    PresumedLoc Loc, AvailabilitySet Availabilities,
+                    const DocComment &Comment, DeclarationFragments Declaration,
+                    DeclarationFragments SubHeading, AccessControl Access,
+                    bool IsFromSystemHeader) {
+  auto Record = std::make_unique<CXXFieldRecord>(
+      USR, Name, Loc, std::move(Availabilities), Comment, Declaration,
+      SubHeading, Access, IsFromSystemHeader);
+  Record->ParentInformation = APIRecord::HierarchyInformation(
+      CXXClass->USR, CXXClass->Name, CXXClass->getKind(), CXXClass);
+  USRBasedLookupTable.insert({USR, Record.get()});
+  return CXXClass->Fields.emplace_back(std::move(Record)).get();
+}
+
+CXXClassRecord *
+APISet::addCXXClass(StringRef Name, StringRef USR, PresumedLoc Loc,
+                    AvailabilitySet Availabilities, const DocComment &Comment,
+                    DeclarationFragments Declaration,
+                    DeclarationFragments SubHeading, APIRecord::RecordKind Kind,
+                    bool IsFromSystemHeader) {
+  return addTopLevelRecord(USRBasedLookupTable, CXXClasses, USR, Name, Loc,
+                           std::move(Availabilities), Comment, Declaration,
+                           SubHeading, Kind, IsFromSystemHeader);
+}
+
+CXXMethodRecord *APISet::addCXXMethod(
+    CXXClassRecord *CXXClassRecord, StringRef Name, StringRef USR,
+    PresumedLoc Loc, AvailabilitySet Availability, const DocComment &Comment,
+    DeclarationFragments Declaration, DeclarationFragments SubHeading,
+    FunctionSignature Signature, bool IsStatic, AccessControl Access,
+    bool IsFromSystemHeader) {
+  std::unique_ptr<CXXMethodRecord> Record;
+  if (IsStatic)
+    Record = std::make_unique<CXXStaticMethodRecord>(
+        USR, Name, Loc, std::move(Availability), Comment, Declaration,
+        SubHeading, Signature, Access, IsFromSystemHeader);
+  else
+    Record = std::make_unique<CXXInstanceMethodRecord>(
+        USR, Name, Loc, std::move(Availability), Comment, Declaration,
+        SubHeading, Signature, Access, IsFromSystemHeader);
+
+  Record->ParentInformation = APIRecord::HierarchyInformation(
+      CXXClassRecord->USR, CXXClassRecord->Name, CXXClassRecord->getKind(),
+      CXXClassRecord);
+  USRBasedLookupTable.insert({USR, Record.get()});
+  return CXXClassRecord->Methods.emplace_back(std::move(Record)).get();
+}
+
+CXXMethodRecord *APISet::addCXXSpecialMethod(
+    CXXClassRecord *CXXClassRecord, StringRef Name, StringRef USR,
+    PresumedLoc Loc, AvailabilitySet Availability, const DocComment &Comment,
+    DeclarationFragments Declaration, DeclarationFragments SubHeading,
+    FunctionSignature Signature, bool IsConstructor, AccessControl Access,
+    bool IsFromSystemHeader) {
+  std::unique_ptr<CXXMethodRecord> Record;
+  if (IsConstructor)
+    Record = std::make_unique<CXXConstructorRecord>(
+        USR, Name, Loc, std::move(Availability), Comment, Declaration,
+        SubHeading, Signature, Access, IsFromSystemHeader);
+  else
+    Record = std::make_unique<CXXDestructorRecord>(
+        USR, Name, Loc, std::move(Availability), Comment, Declaration,
+        SubHeading, Signature, Access, IsFromSystemHeader);
+
+  Record->ParentInformation = APIRecord::HierarchyInformation(
+      CXXClassRecord->USR, CXXClassRecord->Name, CXXClassRecord->getKind(),
+      CXXClassRecord);
+  USRBasedLookupTable.insert({USR, Record.get()});
+  return CXXClassRecord->Methods.emplace_back(std::move(Record)).get();
+}
+
 ObjCCategoryRecord *APISet::addObjCCategory(
     StringRef Name, StringRef USR, PresumedLoc Loc,
     AvailabilitySet Availabilities, const DocComment &Comment,
@@ -285,6 +370,7 @@
 ObjCContainerRecord::~ObjCContainerRecord() {}
 ObjCMethodRecord::~ObjCMethodRecord() {}
 ObjCPropertyRecord::~ObjCPropertyRecord() {}
+CXXMethodRecord::~CXXMethodRecord() {}
 
 void GlobalFunctionRecord::anchor() {}
 void GlobalVariableRecord::anchor() {}
@@ -292,6 +378,12 @@
 void EnumRecord::anchor() {}
 void StructFieldRecord::anchor() {}
 void StructRecord::anchor() {}
+void CXXFieldRecord::anchor() {}
+void CXXClassRecord::anchor() {}
+void CXXConstructorRecord::anchor() {}
+void CXXDestructorRecord::anchor() {}
+void CXXInstanceMethodRecord::anchor() {}
+void CXXStaticMethodRecord::anchor() {}
 void ObjCInstancePropertyRecord::anchor() {}
 void ObjCClassPropertyRecord::anchor() {}
 void ObjCInstanceVariableRecord::anchor() {}
Index: clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
===================================================================
--- clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
+++ clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
@@ -160,6 +160,10 @@
   /// Visit a struct record.
   void visitStructRecord(const StructRecord &Record);
 
+  void visitStaticFieldRecord(const StaticFieldRecord &Record);
+
+  void visitCXXClassRecord(const CXXClassRecord &Record);
+
   /// Visit an Objective-C container record.
   void visitObjCContainerRecord(const ObjCContainerRecord &Record);
 
Index: clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
===================================================================
--- clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
+++ clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
@@ -29,6 +29,10 @@
 
     getDerived()->traverseEnumRecords();
 
+    getDerived()->traverseStaticFieldRecords();
+
+    getDerived()->traverseCXXClassRecords();
+
     getDerived()->traverseStructRecords();
 
     getDerived()->traverseObjCInterfaces();
@@ -60,6 +64,16 @@
       getDerived()->visitStructRecord(*Struct.second);
   }
 
+  void traverseStaticFieldRecords() {
+    for (const auto &StaticField : API.getStaticFields())
+      getDerived()->visitStaticFieldRecord(*StaticField.second);
+  }
+
+  void traverseCXXClassRecords() {
+    for (const auto &Class : API.getCXXClasses())
+      getDerived()->visitCXXClassRecord(*Class.second);
+  }
+
   void traverseObjCInterfaces() {
     for (const auto &Interface : API.getObjCInterfaces())
       getDerived()->visitObjCContainerRecord(*Interface.second);
@@ -92,6 +106,10 @@
   /// Visit a struct record.
   void visitStructRecord(const StructRecord &Record){};
 
+  void visitStaticFieldRecord(const StaticFieldRecord &Record){};
+
+  void visitCXXClassRecord(const CXXClassRecord &Record){};
+
   /// Visit an Objective-C container record.
   void visitObjCContainerRecord(const ObjCContainerRecord &Record){};
 
Index: clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
===================================================================
--- clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
+++ clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
@@ -14,6 +14,7 @@
 #ifndef LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H
 #define LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H
 
+#include "clang/ExtractAPI/DeclarationFragments.h"
 #include "llvm/ADT/FunctionExtras.h"
 
 #include "clang/AST/ASTContext.h"
@@ -44,8 +45,12 @@
 
   bool VisitEnumDecl(const EnumDecl *Decl);
 
+  bool WalkUpFromRecordDecl(const RecordDecl *Decl);
+
   bool VisitRecordDecl(const RecordDecl *Decl);
 
+  bool VisitCXXRecordDecl(const CXXRecordDecl *Decl);
+
   bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl);
 
   bool VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl);
@@ -69,6 +74,17 @@
   void recordStructFields(StructRecord *StructRecord,
                           const RecordDecl::field_range Fields);
 
+  /// Collect API information for the class fields and associate with the parent
+  /// struct
+  void recordCXXFields(CXXClassRecord *CXXClassRecord,
+                       const RecordDecl::field_range Fields);
+
+  void recordCXXMethods(CXXClassRecord *CXXClassRecord,
+                        const CXXRecordDecl::method_range Methods);
+
+  void recordSpecialCXXMethod(CXXClassRecord *CXXClassRecord,
+                              const CXXMethodDecl *SpecialCXXMethod);
+
   /// Collect API information for the Objective-C methods and associate with the
   /// parent container.
   void recordObjCMethods(ObjCContainerRecord *Container,
@@ -131,8 +147,9 @@
   if (isa<ParmVarDecl>(Decl))
     return true;
 
-  // Skip non-global variables in records (struct/union/class).
-  if (Decl->getDeclContext()->isRecord())
+  // Skip non-global variables in records (struct/union/class) but not static
+  // members.
+  if (Decl->getDeclContext()->isRecord() && !Decl->isStaticDataMember())
     return true;
 
   // Skip local variables inside function or method.
@@ -165,9 +182,19 @@
   DeclarationFragments SubHeading =
       DeclarationFragmentsBuilder::getSubHeading(Decl);
 
-  // Add the global variable record to the API set.
-  API.addGlobalVar(Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment,
-                   Declaration, SubHeading, isInSystemHeader(Decl));
+  if (Decl->isStaticDataMember()) {
+    SymbolReference Context;
+    auto Record = dyn_cast<RecordDecl>(Decl->getDeclContext());
+    Context.Name = Record->getName();
+    Context.USR = API.recordUSR(Record);
+    auto Access = DeclarationFragmentsBuilder::getAccessControl(Decl);
+    API.addStaticField(Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment,
+                       Declaration, SubHeading, Context, Access,
+                       isInSystemHeader(Decl));
+  } else
+    // Add the global variable record to the API set.
+    API.addGlobalVar(Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment,
+                     Declaration, SubHeading, isInSystemHeader(Decl));
   return true;
 }
 
@@ -280,15 +307,20 @@
 }
 
 template <typename Derived>
-bool ExtractAPIVisitorBase<Derived>::VisitRecordDecl(const RecordDecl *Decl) {
-  // Skip C++ structs/classes/unions
-  // TODO: support C++ records
-  if (isa<CXXRecordDecl>(Decl))
-    return true;
+bool ExtractAPIVisitorBase<Derived>::WalkUpFromRecordDecl(
+    const RecordDecl *Decl) {
+  if (isa<CXXRecordDecl>(Decl)) {
+    VisitCXXRecordDecl(dyn_cast<CXXRecordDecl>(Decl));
+  } else {
+    VisitRecordDecl(Decl);
+  }
+  return true;
+}
 
+template <typename Derived>
+bool ExtractAPIVisitorBase<Derived>::VisitRecordDecl(const RecordDecl *Decl) {
   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
     return true;
-
   // Collect symbol information.
   StringRef Name = Decl->getName();
   if (Name.empty())
@@ -322,6 +354,54 @@
   return true;
 }
 
+template <typename Derived>
+bool ExtractAPIVisitorBase<Derived>::VisitCXXRecordDecl(
+    const CXXRecordDecl *Decl) {
+  if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
+    return true;
+
+  StringRef Name = Decl->getName();
+  StringRef USR = API.recordUSR(Decl);
+  PresumedLoc Loc =
+      Context.getSourceManager().getPresumedLoc(Decl->getLocation());
+  DocComment Comment;
+  if (auto *RawComment =
+          getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
+    Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+                                            Context.getDiagnostics());
+  DeclarationFragments Declaration =
+      DeclarationFragmentsBuilder::getFragmentsForCXXClass(Decl);
+  DeclarationFragments SubHeading =
+      DeclarationFragmentsBuilder::getSubHeading(Decl);
+
+  APIRecord::RecordKind Kind;
+  if (Decl->isUnion())
+    Kind = APIRecord::RecordKind::RK_Union;
+  else if (Decl->isStruct())
+    Kind = APIRecord::RecordKind::RK_Struct;
+  else
+    Kind = APIRecord::RecordKind::RK_CXXClass;
+
+  CXXClassRecord *CXXClassRecord =
+      API.addCXXClass(Name, USR, Loc, AvailabilitySet(Decl), Comment,
+                      Declaration, SubHeading, Kind, isInSystemHeader(Decl));
+
+  // FIXME: store AccessSpecifier given by inheritance
+  for (const auto BaseSpecifier : Decl->bases()) {
+    SymbolReference BaseClass;
+    CXXRecordDecl *BaseClassDecl =
+        BaseSpecifier.getType().getTypePtr()->getAsCXXRecordDecl();
+    BaseClass.Name = BaseClassDecl->getName();
+    BaseClass.USR = API.recordUSR(BaseClassDecl);
+    CXXClassRecord->Bases.emplace_back(BaseClass);
+  }
+
+  getDerivedExtractAPIVisitor().recordCXXFields(CXXClassRecord, Decl->fields());
+  getDerivedExtractAPIVisitor().recordCXXMethods(CXXClassRecord,
+                                                 Decl->methods());
+  return true;
+}
+
 template <typename Derived>
 bool ExtractAPIVisitorBase<Derived>::VisitObjCInterfaceDecl(
     const ObjCInterfaceDecl *Decl) {
@@ -558,6 +638,107 @@
   }
 }
 
+template <typename Derived>
+void ExtractAPIVisitorBase<Derived>::recordCXXFields(
+    CXXClassRecord *CXXClassRecord, const RecordDecl::field_range Fields) {
+  for (const auto *Field : Fields) {
+    // Collect symbol information.
+    StringRef Name = Field->getName();
+    StringRef USR = API.recordUSR(Field);
+    PresumedLoc Loc =
+        Context.getSourceManager().getPresumedLoc(Field->getLocation());
+    Context.getSourceManager().getPresumedLoc(Field->getLocation());
+    DocComment Comment;
+    if (auto *RawComment =
+            getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Field))
+      Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+                                              Context.getDiagnostics());
+
+    // Build declaration fragments and sub-heading for the struct field.
+    DeclarationFragments Declaration =
+        DeclarationFragmentsBuilder::getFragmentsForField(Field);
+    DeclarationFragments SubHeading =
+        DeclarationFragmentsBuilder::getSubHeading(Field);
+    AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Field);
+
+    API.addCXXField(CXXClassRecord, Name, USR, Loc, AvailabilitySet(Field),
+                    Comment, Declaration, SubHeading, Access,
+                    isInSystemHeader(Field));
+  }
+}
+
+template <typename Derived>
+void ExtractAPIVisitorBase<Derived>::recordSpecialCXXMethod(
+    CXXClassRecord *CXXClassRecord, const CXXMethodDecl *CXXSpecialMethod) {
+  StringRef Name;
+  bool isConstructor = false;
+  if (isa<CXXConstructorDecl>(CXXSpecialMethod)) {
+    isConstructor = true;
+    Name = CXXClassRecord->Name;
+  } else if (isa<CXXDestructorDecl>(CXXSpecialMethod)) {
+    Name = CXXClassRecord->Name;
+  }
+
+  StringRef USR = API.recordUSR(CXXSpecialMethod);
+  PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(
+      CXXSpecialMethod->getLocation());
+  DocComment Comment;
+  if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(
+          CXXSpecialMethod))
+    Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+                                            Context.getDiagnostics());
+
+  // Build declaration fragments, sub-heading, and signature for the method.
+  DeclarationFragments Declaration =
+      DeclarationFragmentsBuilder::getFragmentsForCXXMethod(CXXSpecialMethod);
+  DeclarationFragments SubHeading =
+      DeclarationFragmentsBuilder::getSubHeading(CXXSpecialMethod);
+  FunctionSignature Signature =
+      DeclarationFragmentsBuilder::getFunctionSignature(CXXSpecialMethod);
+  AccessControl Access =
+      DeclarationFragmentsBuilder::getAccessControl(CXXSpecialMethod);
+
+  API.addCXXSpecialMethod(CXXClassRecord, Name, USR, Loc,
+                          AvailabilitySet(CXXSpecialMethod), Comment,
+                          Declaration, SubHeading, Signature, isConstructor,
+                          Access, isInSystemHeader(CXXSpecialMethod));
+}
+
+template <typename Derived>
+void ExtractAPIVisitorBase<Derived>::recordCXXMethods(
+    CXXClassRecord *CXXClassRecord, const CXXRecordDecl::method_range Methods) {
+  for (const auto *Method : Methods) {
+    if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method)) {
+      recordSpecialCXXMethod(CXXClassRecord, Method);
+      continue;
+    }
+
+    StringRef Name = API.copyString(Method->getNameAsString());
+    StringRef USR = API.recordUSR(Method);
+    PresumedLoc Loc =
+        Context.getSourceManager().getPresumedLoc(Method->getLocation());
+    DocComment Comment;
+    if (auto *RawComment =
+            getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Method))
+      Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+                                              Context.getDiagnostics());
+
+    // Build declaration fragments, sub-heading, and signature for the method.
+    DeclarationFragments Declaration =
+        DeclarationFragmentsBuilder::getFragmentsForCXXMethod(Method);
+    DeclarationFragments SubHeading =
+        DeclarationFragmentsBuilder::getSubHeading(Method);
+    FunctionSignature Signature =
+        DeclarationFragmentsBuilder::getFunctionSignature(Method);
+    AccessControl Access =
+        DeclarationFragmentsBuilder::getAccessControl(Method);
+
+    API.addCXXMethod(CXXClassRecord, Name, USR, Loc, AvailabilitySet(Method),
+                     Comment, Declaration, SubHeading, Signature,
+                     Method->isStatic(), Access, isInSystemHeader(Method));
+  }
+}
+
 /// Collect API information for the Objective-C methods and associate with the
 /// parent container.
 template <typename Derived>
Index: clang/include/clang/ExtractAPI/DeclarationFragments.h
===================================================================
--- clang/include/clang/ExtractAPI/DeclarationFragments.h
+++ clang/include/clang/ExtractAPI/DeclarationFragments.h
@@ -20,8 +20,10 @@
 
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
+#include "clang/Basic/Specifiers.h"
 #include "clang/Lex/MacroInfo.h"
 #include "llvm/ADT/StringRef.h"
 #include <vector>
@@ -173,10 +175,29 @@
   /// Get the corresponding FragmentKind from string \p S.
   static FragmentKind parseFragmentKindFromString(StringRef S);
 
+  static DeclarationFragments
+  getExceptionSpecificationString(ExceptionSpecificationType ExceptionSpec);
+
+  static DeclarationFragments getStructureTypeFragment(const RecordDecl *Decl);
+
 private:
   std::vector<Fragment> Fragments;
 };
 
+class AccessControl {
+public:
+  AccessControl() = default;
+
+  const StringRef &getAccess() const { return Access; }
+
+  void setAccess(StringRef Acc) { Access = Acc; }
+
+  bool empty() const { return Access.empty(); }
+
+private:
+  StringRef Access;
+};
+
 /// Store function signature information with DeclarationFragments of the
 /// return type and parameters.
 class FunctionSignature {
@@ -219,6 +240,49 @@
 /// A factory class to build DeclarationFragments for different kinds of Decl.
 class DeclarationFragmentsBuilder {
 public:
+  /// Build FunctionSignature for a function-like declaration \c FunctionT like
+  /// FunctionDecl or ObjCMethodDecl.
+  ///
+  /// The logic and implementation of building a signature for a FunctionDecl
+  /// and an ObjCMethodDecl are exactly the same, but they do not share a common
+  /// base. This template helps reuse the code.
+  template <typename FunctionT>
+  static FunctionSignature getFunctionSignature(const FunctionT *Function) {
+    FunctionSignature Signature;
+
+    DeclarationFragments ReturnType, After;
+    ReturnType
+        .append(getFragmentsForType(Function->getReturnType(),
+                                    Function->getASTContext(), After))
+        .append(std::move(After));
+    Signature.setReturnType(ReturnType);
+
+    for (const auto *Param : Function->parameters())
+      Signature.addParameter(Param->getName(), getFragmentsForParam(Param));
+
+    return Signature;
+  }
+
+  static AccessControl getAccessControl(const Decl *Decl) {
+    AccessControl AccessControl;
+
+    switch (Decl->getAccess()) {
+    case AS_public:
+      AccessControl.setAccess("public");
+      break;
+    case AS_private:
+      AccessControl.setAccess("private");
+      break;
+    case AS_protected:
+      AccessControl.setAccess("protected");
+      break;
+    case AS_none:
+      AccessControl.setAccess("none");
+      break;
+    }
+    return AccessControl;
+  }
+
   /// Build DeclarationFragments for a variable declaration VarDecl.
   static DeclarationFragments getFragmentsForVar(const VarDecl *);
 
@@ -239,6 +303,10 @@
   /// Build DeclarationFragments for a struct record declaration RecordDecl.
   static DeclarationFragments getFragmentsForStruct(const RecordDecl *);
 
+  static DeclarationFragments getFragmentsForCXXClass(const CXXRecordDecl *);
+
+  static DeclarationFragments getFragmentsForCXXMethod(const CXXMethodDecl *);
+
   /// Build DeclarationFragments for an Objective-C category declaration
   /// ObjCCategoryDecl.
   static DeclarationFragments
@@ -283,15 +351,6 @@
   /// Build a sub-heading for macro \p Name.
   static DeclarationFragments getSubHeadingForMacro(StringRef Name);
 
-  /// Build FunctionSignature for a function-like declaration \c FunctionT like
-  /// FunctionDecl or ObjCMethodDecl.
-  ///
-  /// The logic and implementation of building a signature for a FunctionDecl
-  /// and an ObjCMethodDecl are exactly the same, but they do not share a common
-  /// base. This template helps reuse the code.
-  template <typename FunctionT>
-  static FunctionSignature getFunctionSignature(const FunctionT *);
-
 private:
   DeclarationFragmentsBuilder() = delete;
 
Index: clang/include/clang/ExtractAPI/API.h
===================================================================
--- clang/include/clang/ExtractAPI/API.h
+++ clang/include/clang/ExtractAPI/API.h
@@ -22,6 +22,7 @@
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/RawCommentList.h"
 #include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/Specifiers.h"
 #include "clang/ExtractAPI/AvailabilityInfo.h"
 #include "clang/ExtractAPI/DeclarationFragments.h"
 #include "llvm/ADT/MapVector.h"
@@ -64,6 +65,14 @@
     RK_Enum,
     RK_StructField,
     RK_Struct,
+    RK_Union,
+    RK_StaticField,
+    RK_CXXField,
+    RK_CXXClass,
+    RK_CXXStaticMethod,
+    RK_CXXInstanceMethod,
+    RK_CXXConstructorMethod,
+    RK_CXXDestructorMethod,
     RK_ObjCInstanceProperty,
     RK_ObjCClassProperty,
     RK_ObjCIvar,
@@ -266,6 +275,132 @@
   virtual void anchor();
 };
 
+struct CXXFieldRecord : APIRecord {
+  AccessControl Access;
+
+  CXXFieldRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
+                 AvailabilitySet Availabilities, const DocComment &Comment,
+                 DeclarationFragments Declaration,
+                 DeclarationFragments SubHeading, AccessControl Access,
+                 bool IsFromSystemHeader)
+      : APIRecord(RK_CXXField, USR, Name, Loc, std::move(Availabilities),
+                  LinkageInfo::none(), Comment, Declaration, SubHeading,
+                  IsFromSystemHeader),
+        Access(Access) {}
+
+  CXXFieldRecord(RecordKind Kind, StringRef USR, StringRef Name,
+                 PresumedLoc Loc, AvailabilitySet Availabilities,
+                 const DocComment &Comment, DeclarationFragments Declaration,
+                 DeclarationFragments SubHeading, AccessControl Access,
+                 bool IsFromSystemHeader)
+      : APIRecord(Kind, USR, Name, Loc, std::move(Availabilities),
+                  LinkageInfo::none(), Comment, Declaration, SubHeading,
+                  IsFromSystemHeader),
+        Access(Access) {}
+
+  static bool classof(const APIRecord *Record) {
+    return Record->getKind() == RK_CXXField;
+  }
+
+private:
+  virtual void anchor();
+};
+
+struct CXXMethodRecord : APIRecord {
+  FunctionSignature Signature;
+  AccessControl Access;
+
+  CXXMethodRecord() = delete;
+
+  CXXMethodRecord(RecordKind Kind, StringRef USR, StringRef Name,
+                  PresumedLoc Loc, AvailabilitySet Availabilities,
+                  const DocComment &Comment, DeclarationFragments Declaration,
+                  DeclarationFragments SubHeading, FunctionSignature Signature,
+                  AccessControl Access, bool IsFromSystemHeader)
+      : APIRecord(Kind, USR, Name, Loc, std::move(Availabilities),
+                  LinkageInfo::none(), Comment, Declaration, SubHeading,
+                  IsFromSystemHeader),
+        Signature(Signature), Access(Access) {}
+
+  virtual ~CXXMethodRecord() = 0;
+};
+
+struct CXXConstructorRecord : CXXMethodRecord {
+  CXXConstructorRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
+                       AvailabilitySet Availabilities,
+                       const DocComment &Comment,
+                       DeclarationFragments Declaration,
+                       DeclarationFragments SubHeading,
+                       FunctionSignature Signature, AccessControl Access,
+                       bool IsFromSystemHeader)
+      : CXXMethodRecord(RK_CXXConstructorMethod, USR, Name, Loc,
+                        std::move(Availabilities), Comment, Declaration,
+                        SubHeading, Signature, Access, IsFromSystemHeader) {}
+  static bool classof(const APIRecord *Record) {
+    return Record->getKind() == RK_CXXConstructorMethod;
+  }
+
+private:
+  virtual void anchor();
+};
+
+struct CXXDestructorRecord : CXXMethodRecord {
+  CXXDestructorRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
+                      AvailabilitySet Availabilities, const DocComment &Comment,
+                      DeclarationFragments Declaration,
+                      DeclarationFragments SubHeading,
+                      FunctionSignature Signature, AccessControl Access,
+                      bool IsFromSystemHeader)
+      : CXXMethodRecord(RK_CXXDestructorMethod, USR, Name, Loc,
+                        std::move(Availabilities), Comment, Declaration,
+                        SubHeading, Signature, Access, IsFromSystemHeader) {}
+  static bool classof(const APIRecord *Record) {
+    return Record->getKind() == RK_CXXDestructorMethod;
+  }
+
+private:
+  virtual void anchor();
+};
+
+struct CXXStaticMethodRecord : CXXMethodRecord {
+  CXXStaticMethodRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
+                        AvailabilitySet Availabilities,
+                        const DocComment &Comment,
+                        DeclarationFragments Declaration,
+                        DeclarationFragments SubHeading,
+                        FunctionSignature Signature, AccessControl Access,
+                        bool IsFromSystemHeader)
+      : CXXMethodRecord(RK_CXXStaticMethod, USR, Name, Loc,
+                        std::move(Availabilities), Comment, Declaration,
+                        SubHeading, Signature, Access, IsFromSystemHeader) {}
+  static bool classof(const APIRecord *Record) {
+    return Record->getKind() == RK_CXXStaticMethod;
+  }
+
+private:
+  virtual void anchor();
+};
+
+struct CXXInstanceMethodRecord : CXXMethodRecord {
+  CXXInstanceMethodRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
+                          AvailabilitySet Availabilities,
+                          const DocComment &Comment,
+                          DeclarationFragments Declaration,
+                          DeclarationFragments SubHeading,
+                          FunctionSignature Signature, AccessControl Access,
+                          bool IsFromSystemHeader)
+      : CXXMethodRecord(RK_CXXInstanceMethod, USR, Name, Loc,
+                        std::move(Availabilities), Comment, Declaration,
+                        SubHeading, Signature, Access, IsFromSystemHeader) {}
+
+  static bool classof(const APIRecord *Record) {
+    return Record->getKind() == RK_CXXInstanceMethod;
+  }
+
+private:
+  virtual void anchor();
+};
+
 /// This holds information associated with Objective-C properties.
 struct ObjCPropertyRecord : APIRecord {
   /// The attributes associated with an Objective-C property.
@@ -444,6 +579,24 @@
   bool empty() const { return Name.empty() && USR.empty() && Source.empty(); }
 };
 
+struct StaticFieldRecord : CXXFieldRecord {
+  SymbolReference Context;
+
+  StaticFieldRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
+                    AvailabilitySet Availabilities, LinkageInfo Linkage,
+                    const DocComment &Comment, DeclarationFragments Declaration,
+                    DeclarationFragments SubHeading, SymbolReference Context,
+                    AccessControl Access, bool IsFromSystemHeader)
+      : CXXFieldRecord(RK_StaticField, USR, Name, Loc,
+                       std::move(Availabilities), Comment, Declaration,
+                       SubHeading, Access, IsFromSystemHeader),
+        Context(Context) {}
+
+  static bool classof(const APIRecord *Record) {
+    return Record->getKind() == RK_StaticField;
+  }
+};
+
 /// The base representation of an Objective-C container record. Holds common
 /// information associated with Objective-C containers.
 struct ObjCContainerRecord : APIRecord {
@@ -465,6 +618,29 @@
   virtual ~ObjCContainerRecord() = 0;
 };
 
+struct CXXClassRecord : APIRecord {
+  SmallVector<std::unique_ptr<CXXFieldRecord>> Fields;
+  SmallVector<std::unique_ptr<CXXMethodRecord>> Methods;
+  SmallVector<SymbolReference> Bases;
+
+  CXXClassRecord(StringRef USR, StringRef Name, PresumedLoc Loc,
+                 AvailabilitySet Availabilities, const DocComment &Comment,
+                 DeclarationFragments Declaration,
+                 DeclarationFragments SubHeading, RecordKind Kind,
+                 bool IsFromSystemHeader)
+      : APIRecord(Kind, USR, Name, Loc, std::move(Availabilities),
+                  LinkageInfo::none(), Comment, Declaration, SubHeading,
+                  IsFromSystemHeader) {}
+
+  static bool classof(const APIRecord *Record) {
+    return (Record->getKind() == RK_CXXClass ||
+            Record->getKind() == RK_Struct || Record->getKind() == RK_Union);
+  }
+
+private:
+  virtual void anchor();
+};
+
 /// This holds information associated with Objective-C categories.
 struct ObjCCategoryRecord : ObjCContainerRecord {
   SymbolReference Interface;
@@ -592,6 +768,11 @@
 template <>
 struct has_function_signature<ObjCClassMethodRecord> : public std::true_type {};
 
+template <>
+struct has_function_signature<CXXMethodRecord> : public std::true_type {};
+template <typename RecordTy> struct has_access : public std::false_type {};
+template <> struct has_access<CXXMethodRecord> : public std::true_type {};
+template <> struct has_access<CXXFieldRecord> : public std::true_type {};
 /// APISet holds the set of API records collected from given inputs.
 class APISet {
 public:
@@ -668,6 +849,41 @@
                           DeclarationFragments SubHeading,
                           bool IsFromSystemHeader);
 
+  StaticFieldRecord *
+  addStaticField(StringRef Name, StringRef USR, PresumedLoc Loc,
+                 AvailabilitySet Availabilities, LinkageInfo Linkage,
+                 const DocComment &Comment, DeclarationFragments Declaration,
+                 DeclarationFragments SubHeading, SymbolReference Context,
+                 AccessControl Access, bool IsFromSystemHeaderg);
+
+  CXXFieldRecord *addCXXField(CXXClassRecord *CXXClass, StringRef Name,
+                              StringRef USR, PresumedLoc Loc,
+                              AvailabilitySet Availabilities,
+                              const DocComment &Comment,
+                              DeclarationFragments Declaration,
+                              DeclarationFragments SubHeading,
+                              AccessControl Access, bool IsFromSystemHeader);
+
+  CXXClassRecord *
+  addCXXClass(StringRef Name, StringRef USR, PresumedLoc Loc,
+              AvailabilitySet Availability, const DocComment &Comment,
+              DeclarationFragments Declaration, DeclarationFragments SubHeading,
+              APIRecord::RecordKind Kind, bool IsFromSystemHeader);
+
+  CXXMethodRecord *
+  addCXXMethod(CXXClassRecord *CXXClassRecord, StringRef Name, StringRef USR,
+               PresumedLoc Loc, AvailabilitySet Availability,
+               const DocComment &Comment, DeclarationFragments Declaration,
+               DeclarationFragments SubHeading, FunctionSignature Signature,
+               bool IsStatic, AccessControl Access, bool IsFromSystemHeader);
+
+  CXXMethodRecord *addCXXSpecialMethod(
+      CXXClassRecord *CXXClassRecord, StringRef Name, StringRef USR,
+      PresumedLoc Loc, AvailabilitySet Availability, const DocComment &Comment,
+      DeclarationFragments Declaration, DeclarationFragments SubHeading,
+      FunctionSignature Signature, bool IsConstructor, AccessControl Access,
+      bool IsFromSystemHeader);
+
   /// Create and add an Objective-C category record into the API set.
   ///
   /// Note: the caller is responsible for keeping the StringRef \p Name and
@@ -790,8 +1006,12 @@
   const RecordMap<GlobalVariableRecord> &getGlobalVariables() const {
     return GlobalVariables;
   }
+  const RecordMap<StaticFieldRecord> &getStaticFields() const {
+    return StaticFields;
+  }
   const RecordMap<EnumRecord> &getEnums() const { return Enums; }
   const RecordMap<StructRecord> &getStructs() const { return Structs; }
+  const RecordMap<CXXClassRecord> &getCXXClasses() const { return CXXClasses; }
   const RecordMap<ObjCCategoryRecord> &getObjCCategories() const {
     return ObjCCategories;
   }
@@ -845,8 +1065,10 @@
   llvm::DenseMap<StringRef, APIRecord *> USRBasedLookupTable;
   RecordMap<GlobalFunctionRecord> GlobalFunctions;
   RecordMap<GlobalVariableRecord> GlobalVariables;
+  RecordMap<StaticFieldRecord> StaticFields;
   RecordMap<EnumRecord> Enums;
   RecordMap<StructRecord> Structs;
+  RecordMap<CXXClassRecord> CXXClasses;
   RecordMap<ObjCCategoryRecord> ObjCCategories;
   RecordMap<ObjCInterfaceRecord> ObjCInterfaces;
   RecordMap<ObjCProtocolRecord> ObjCProtocols;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to