[clang] 3bb4855 - [clang][ExtractAPI] Refactor C++ method and field visitation

Erick Velez via cfe-commits cfe-commits at lists.llvm.org
Mon Aug 21 10:38:12 PDT 2023


Author: Erick Velez
Date: 2023-08-21T10:38:01-07:00
New Revision: 3bb485530869d3ea43458b24df5a2d5302553bf9

URL: https://github.com/llvm/llvm-project/commit/3bb485530869d3ea43458b24df5a2d5302553bf9
DIFF: https://github.com/llvm/llvm-project/commit/3bb485530869d3ea43458b24df5a2d5302553bf9.diff

LOG: [clang][ExtractAPI] Refactor C++ method and field visitation

Refactor visitation for C++ record children by following the Visitor's CRTP.
Expand VisitCXXField, VisitCXXMethod for non-templates and introduce VisitCXXConstructor, VisitCXXDestructor.
Handle relationships by finding the parent's Record via USR from DeclContext.

Depends on D158029

Reviewed By: dang

Differential Revision: https://reviews.llvm.org/D158031

Added: 
    

Modified: 
    clang/include/clang/ExtractAPI/API.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/Serialization/SymbolGraphSerializer.cpp
    clang/test/ExtractAPI/constructor_destructor.cpp
    clang/test/ExtractAPI/methods.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/ExtractAPI/API.h b/clang/include/clang/ExtractAPI/API.h
index b855f460b9c7c1..7b2d28f738e260 100644
--- a/clang/include/clang/ExtractAPI/API.h
+++ b/clang/include/clang/ExtractAPI/API.h
@@ -1117,7 +1117,9 @@ struct has_function_signature<ObjCInstanceMethodRecord>
 template <>
 struct has_function_signature<ObjCClassMethodRecord> : public std::true_type {};
 template <>
-struct has_function_signature<CXXMethodRecord> : public std::true_type {};
+struct has_function_signature<CXXInstanceMethodRecord> : public std::true_type {};
+template <>
+struct has_function_signature<CXXStaticMethodRecord> : public std::true_type {};
 template <>
 struct has_function_signature<CXXMethodTemplateRecord> : public std::true_type {
 };
@@ -1126,7 +1128,8 @@ struct has_function_signature<CXXMethodTemplateSpecializationRecord>
     : 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<CXXInstanceMethodRecord> : public std::true_type {};
+template <> struct has_access<CXXStaticMethodRecord> : public std::true_type {};
 template <> struct has_access<CXXFieldRecord> : public std::true_type {};
 template <>
 struct has_access<CXXMethodTemplateRecord> : public std::true_type {};
@@ -1267,7 +1270,7 @@ class APISet {
                  DeclarationFragments SubHeading, SymbolReference Context,
                  AccessControl Access, bool IsFromSystemHeaderg);
 
-  CXXFieldRecord *addCXXField(CXXClassRecord *CXXClass, StringRef Name,
+  CXXFieldRecord *addCXXField(APIRecord *CXXClass, StringRef Name,
                               StringRef USR, PresumedLoc Loc,
                               AvailabilitySet Availabilities,
                               const DocComment &Comment,
@@ -1322,18 +1325,25 @@ class APISet {
       DeclarationFragments SubHeading, Template Template,
       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 *addCXXInstanceMethod(
+      APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc,
+      AvailabilitySet Availability, const DocComment &Comment,
+      DeclarationFragments Declaration, DeclarationFragments SubHeading,
+      FunctionSignature Signature, AccessControl Access,
+      bool IsFromSystemHeader);
+
+  CXXMethodRecord *addCXXStaticMethod(
+      APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc,
+      AvailabilitySet Availability, const DocComment &Comment,
+      DeclarationFragments Declaration, DeclarationFragments SubHeading,
+      FunctionSignature Signature, AccessControl Access,
+      bool IsFromSystemHeader);
 
   CXXMethodRecord *addCXXSpecialMethod(
-      CXXClassRecord *CXXClassRecord, StringRef Name, StringRef USR,
-      PresumedLoc Loc, AvailabilitySet Availability, const DocComment &Comment,
+      APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc,
+      AvailabilitySet Availability, const DocComment &Comment,
       DeclarationFragments Declaration, DeclarationFragments SubHeading,
-      FunctionSignature Signature, bool IsConstructor, AccessControl Access,
+      FunctionSignature Signature, AccessControl Access,
       bool IsFromSystemHeader);
 
   CXXMethodTemplateRecord *addCXXMethodTemplate(
@@ -1508,6 +1518,13 @@ class APISet {
   const RecordMap<CXXMethodTemplateRecord> &getCXXMethodTemplates() const {
     return CXXMethodTemplates;
   }
+  const RecordMap<CXXInstanceMethodRecord> &getCXXInstanceMethods() const {
+    return CXXInstanceMethods;
+  }
+  const RecordMap<CXXStaticMethodRecord> &getCXXStaticMethods() const {
+    return CXXStaticMethods;
+  }
+  const RecordMap<CXXFieldRecord> &getCXXFields() const { return CXXFields; }
   const RecordMap<CXXMethodTemplateSpecializationRecord> &
   getCXXMethodTemplateSpecializations() const {
     return CXXMethodTemplateSpecializations;
@@ -1594,6 +1611,10 @@ class APISet {
   RecordMap<EnumRecord> Enums;
   RecordMap<StructRecord> Structs;
   RecordMap<CXXClassRecord> CXXClasses;
+  RecordMap<CXXFieldRecord> CXXFields;
+  RecordMap<CXXMethodRecord> CXXMethods;
+  RecordMap<CXXInstanceMethodRecord> CXXInstanceMethods;
+  RecordMap<CXXStaticMethodRecord> CXXStaticMethods;
   RecordMap<CXXMethodTemplateRecord> CXXMethodTemplates;
   RecordMap<CXXMethodTemplateSpecializationRecord>
       CXXMethodTemplateSpecializations;

diff  --git a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
index dbe7f78cd33430..38239b09dd484f 100644
--- a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
+++ b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
@@ -50,6 +50,8 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
 
   bool VisitEnumDecl(const EnumDecl *Decl);
 
+  bool WalkUpFromFunctionDecl(const FunctionDecl *Decl);
+
   bool WalkUpFromRecordDecl(const RecordDecl *Decl);
 
   bool WalkUpFromCXXRecordDecl(const CXXRecordDecl *Decl);
@@ -78,6 +80,14 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
 
   bool VisitCXXMethodDecl(const CXXMethodDecl *Decl);
 
+  bool VisitFieldDecl(const FieldDecl *Decl);
+
+  bool VisitCXXConversionDecl(const CXXConversionDecl *Decl);
+
+  bool VisitCXXConstructorDecl(const CXXConstructorDecl *Decl);
+
+  bool VisitCXXDestructorDecl(const CXXDestructorDecl *Decl);
+
   bool VisitConceptDecl(const ConceptDecl *Decl);
 
   bool VisitClassTemplateSpecializationDecl(
@@ -119,20 +129,6 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
   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 recordConversionMethod(CXXClassRecord *CXXClassRecord,
-                              const CXXMethodDecl *SpecialCXXMethod);
-
-  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,
@@ -378,6 +374,13 @@ bool ExtractAPIVisitorBase<Derived>::VisitEnumDecl(const EnumDecl *Decl) {
   return true;
 }
 
+template <typename Derived>
+bool ExtractAPIVisitorBase<Derived>::WalkUpFromFunctionDecl(
+    const FunctionDecl *Decl) {
+  getDerivedExtractAPIVisitor().VisitFunctionDecl(Decl);
+  return true;
+}
+
 template <typename Derived>
 bool ExtractAPIVisitorBase<Derived>::WalkUpFromRecordDecl(
     const RecordDecl *Decl) {
@@ -527,9 +530,6 @@ bool ExtractAPIVisitorBase<Derived>::VisitCXXRecordDecl(
 
   CXXClassRecord->Bases = getBases(Decl);
 
-  getDerivedExtractAPIVisitor().recordCXXFields(CXXClassRecord, Decl->fields());
-  getDerivedExtractAPIVisitor().recordCXXMethods(CXXClassRecord,
-                                                 Decl->methods());
   return true;
 }
 
@@ -539,18 +539,12 @@ bool ExtractAPIVisitorBase<Derived>::VisitCXXMethodDecl(
   if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl) ||
       Decl->isImplicit())
     return true;
-  switch (Decl->getTemplatedKind()) {
-  case FunctionDecl::TK_MemberSpecialization:
-  case FunctionDecl::TK_FunctionTemplateSpecialization:
-  case FunctionDecl::TK_FunctionTemplate:
-  case FunctionDecl::TK_DependentFunctionTemplateSpecialization:
-    break;
-  case FunctionDecl::TK_NonTemplate:
-  case FunctionDecl::TK_DependentNonTemplate:
+
+  if (isa<CXXConversionDecl>(Decl))
+    return true;
+  if (isa<CXXConstructorDecl>(Decl) || isa<CXXDestructorDecl>(Decl))
     return true;
-  }
 
-  StringRef Name = Decl->getName();
   StringRef USR = API.recordUSR(Decl);
   PresumedLoc Loc =
       Context.getSourceManager().getPresumedLoc(Decl->getLocation());
@@ -561,15 +555,18 @@ bool ExtractAPIVisitorBase<Derived>::VisitCXXMethodDecl(
                                             Context.getDiagnostics());
   DeclarationFragments SubHeading =
       DeclarationFragmentsBuilder::getSubHeading(Decl);
+  auto Access = DeclarationFragmentsBuilder::getAccessControl(Decl);
+  auto Signature = DeclarationFragmentsBuilder::getFunctionSignature(Decl);
 
   SmallString<128> ParentUSR;
   index::generateUSRForDecl(dyn_cast<CXXRecordDecl>(Decl->getDeclContext()),
                             ParentUSR);
+  auto *Parent = API.findRecordForUSR(ParentUSR);
   if (Decl->isTemplated()) {
     FunctionTemplateDecl *TemplateDecl = Decl->getDescribedFunctionTemplate();
     API.addCXXMethodTemplate(
-        API.findRecordForUSR(ParentUSR), Name, USR, Loc, AvailabilitySet(Decl),
-        Comment,
+        API.findRecordForUSR(ParentUSR), Decl->getName(), USR, Loc,
+        AvailabilitySet(Decl), Comment,
         DeclarationFragmentsBuilder::getFragmentsForFunctionTemplate(
             TemplateDecl),
         SubHeading, DeclarationFragmentsBuilder::getFunctionSignature(Decl),
@@ -577,13 +574,93 @@ bool ExtractAPIVisitorBase<Derived>::VisitCXXMethodDecl(
         Template(TemplateDecl), isInSystemHeader(Decl));
   } else if (Decl->getTemplateSpecializationInfo())
     API.addCXXMethodTemplateSpec(
-        API.findRecordForUSR(ParentUSR), Name, USR, Loc, AvailabilitySet(Decl),
-        Comment,
+        Parent, Decl->getName(), USR, Loc, AvailabilitySet(Decl), Comment,
         DeclarationFragmentsBuilder::
             getFragmentsForFunctionTemplateSpecialization(Decl),
-        SubHeading, DeclarationFragmentsBuilder::getFunctionSignature(Decl),
-        DeclarationFragmentsBuilder::getAccessControl(Decl),
-        isInSystemHeader(Decl));
+        SubHeading, Signature, Access, isInSystemHeader(Decl));
+  else if (Decl->isOverloadedOperator())
+    API.addCXXInstanceMethod(
+        Parent, API.copyString(Decl->getNameAsString()), USR, Loc,
+        AvailabilitySet(Decl), Comment,
+        DeclarationFragmentsBuilder::getFragmentsForOverloadedOperator(Decl),
+        SubHeading, Signature, Access, isInSystemHeader(Decl));
+  else if (Decl->isStatic())
+    API.addCXXStaticMethod(
+        Parent, Decl->getName(), USR, Loc, AvailabilitySet(Decl), Comment,
+        DeclarationFragmentsBuilder::getFragmentsForCXXMethod(Decl), SubHeading,
+        Signature, Access, isInSystemHeader(Decl));
+  else
+    API.addCXXInstanceMethod(
+        Parent, Decl->getName(), USR, Loc, AvailabilitySet(Decl), Comment,
+        DeclarationFragmentsBuilder::getFragmentsForCXXMethod(Decl), SubHeading,
+        Signature, Access, isInSystemHeader(Decl));
+
+  return true;
+}
+
+template <typename Derived>
+bool ExtractAPIVisitorBase<Derived>::VisitCXXConstructorDecl(
+    const CXXConstructorDecl *Decl) {
+
+  StringRef Name = API.copyString(Decl->getNameAsString());
+  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());
+
+  // Build declaration fragments, sub-heading, and signature for the method.
+  DeclarationFragments Declaration =
+      DeclarationFragmentsBuilder::getFragmentsForSpecialCXXMethod(Decl);
+  DeclarationFragments SubHeading =
+      DeclarationFragmentsBuilder::getSubHeading(Decl);
+  FunctionSignature Signature =
+      DeclarationFragmentsBuilder::getFunctionSignature(Decl);
+  AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl);
+
+  SmallString<128> ParentUSR;
+  index::generateUSRForDecl(dyn_cast<CXXRecordDecl>(Decl->getDeclContext()),
+                            ParentUSR);
+  API.addCXXInstanceMethod(API.findRecordForUSR(ParentUSR), Name, USR, Loc,
+                           AvailabilitySet(Decl), Comment, Declaration,
+                           SubHeading, Signature, Access,
+                           isInSystemHeader(Decl));
+  return true;
+}
+
+template <typename Derived>
+bool ExtractAPIVisitorBase<Derived>::VisitCXXDestructorDecl(
+    const CXXDestructorDecl *Decl) {
+
+  StringRef Name = API.copyString(Decl->getNameAsString());
+  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());
+
+  // Build declaration fragments, sub-heading, and signature for the method.
+  DeclarationFragments Declaration =
+      DeclarationFragmentsBuilder::getFragmentsForSpecialCXXMethod(Decl);
+  DeclarationFragments SubHeading =
+      DeclarationFragmentsBuilder::getSubHeading(Decl);
+  FunctionSignature Signature =
+      DeclarationFragmentsBuilder::getFunctionSignature(Decl);
+  AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl);
+
+  SmallString<128> ParentUSR;
+  index::generateUSRForDecl(dyn_cast<CXXRecordDecl>(Decl->getDeclContext()),
+                            ParentUSR);
+  API.addCXXInstanceMethod(API.findRecordForUSR(ParentUSR), Name, USR, Loc,
+                           AvailabilitySet(Decl), Comment, Declaration,
+                           SubHeading, Signature, Access,
+                           isInSystemHeader(Decl));
   return true;
 }
 
@@ -636,10 +713,7 @@ bool ExtractAPIVisitorBase<Derived>::VisitClassTemplateSpecializationDecl(
       isInSystemHeader(Decl));
 
   ClassTemplateSpecializationRecord->Bases = getBases(Decl);
-  getDerivedExtractAPIVisitor().recordCXXFields(
-      ClassTemplateSpecializationRecord, Decl->fields());
-  getDerivedExtractAPIVisitor().recordCXXMethods(
-      ClassTemplateSpecializationRecord, Decl->methods());
+
   return true;
 }
 
@@ -671,10 +745,6 @@ bool ExtractAPIVisitorBase<Derived>::
 
   ClassTemplatePartialSpecRecord->Bases = getBases(Decl);
 
-  getDerivedExtractAPIVisitor().recordCXXFields(ClassTemplatePartialSpecRecord,
-                                                Decl->fields());
-  getDerivedExtractAPIVisitor().recordCXXMethods(ClassTemplatePartialSpecRecord,
-                                                 Decl->methods());
   return true;
 }
 
@@ -1063,155 +1133,74 @@ void ExtractAPIVisitorBase<Derived>::recordStructFields(
 }
 
 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));
-  }
-}
-
-/// Collect API information for constructors and destructors and associate with
-/// the parent class.
-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)) {
-    // Copy string to get name with '~'.
-    Name = API.copyString(CXXSpecialMethod->getNameAsString());
-  }
-
-  StringRef USR = API.recordUSR(CXXSpecialMethod);
-  PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(
-      CXXSpecialMethod->getLocation());
+bool ExtractAPIVisitorBase<Derived>::VisitFieldDecl(const FieldDecl *Decl) {
+  if (Decl->getDeclContext()->getDeclKind() == Decl::Record)
+    return true;
+  if (isa<ObjCIvarDecl>(Decl))
+    return true;
+  // Collect symbol information.
+  StringRef Name = Decl->getName();
+  StringRef USR = API.recordUSR(Decl);
+  PresumedLoc Loc =
+      Context.getSourceManager().getPresumedLoc(Decl->getLocation());
   DocComment Comment;
-  if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(
-          CXXSpecialMethod))
+  if (auto *RawComment =
+          getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
                                             Context.getDiagnostics());
 
-  // Build declaration fragments, sub-heading, and signature for the method.
+  // Build declaration fragments and sub-heading for the struct field.
   DeclarationFragments Declaration =
-      DeclarationFragmentsBuilder::getFragmentsForSpecialCXXMethod(
-          CXXSpecialMethod);
+      DeclarationFragmentsBuilder::getFragmentsForField(Decl);
   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));
+      DeclarationFragmentsBuilder::getSubHeading(Decl);
+  AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl);
+
+  SmallString<128> ParentUSR;
+  index::generateUSRForDecl(dyn_cast<CXXRecordDecl>(Decl->getDeclContext()),
+                            ParentUSR);
+  API.addCXXField(API.findRecordForUSR(ParentUSR), Name, USR, Loc,
+                  AvailabilitySet(Decl), Comment, Declaration, SubHeading,
+                  Access, isInSystemHeader(Decl));
+  return true;
 }
 
 template <typename Derived>
-void ExtractAPIVisitorBase<Derived>::recordConversionMethod(
-    CXXClassRecord *CXXClassRecord, const CXXMethodDecl *SpecialCXXMethod) {
-  StringRef Name = API.copyString(SpecialCXXMethod->getNameAsString());
-  StringRef USR = API.recordUSR(SpecialCXXMethod);
-  PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(
-      SpecialCXXMethod->getLocation());
+bool ExtractAPIVisitorBase<Derived>::VisitCXXConversionDecl(
+    const CXXConversionDecl *Decl) {
+  StringRef Name = API.copyString(Decl->getNameAsString());
+  StringRef USR = API.recordUSR(Decl);
+  PresumedLoc Loc =
+      Context.getSourceManager().getPresumedLoc(Decl->getLocation());
   DocComment Comment;
-  if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(
-          SpecialCXXMethod))
+  if (auto *RawComment =
+          getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
     Comment = RawComment->getFormattedLines(Context.getSourceManager(),
                                             Context.getDiagnostics());
 
   // Build declaration fragments, sub-heading, and signature for the method.
   DeclarationFragments Declaration =
-      DeclarationFragmentsBuilder::getFragmentsForConversionFunction(
-          cast<CXXConversionDecl>(SpecialCXXMethod));
+      DeclarationFragmentsBuilder::getFragmentsForConversionFunction(Decl);
   DeclarationFragments SubHeading =
-      DeclarationFragmentsBuilder::getSubHeading(SpecialCXXMethod);
+      DeclarationFragmentsBuilder::getSubHeading(Decl);
   FunctionSignature Signature =
-      DeclarationFragmentsBuilder::getFunctionSignature(SpecialCXXMethod);
-  AccessControl Access =
-      DeclarationFragmentsBuilder::getAccessControl(SpecialCXXMethod);
-
-  API.addCXXMethod(CXXClassRecord, Name, USR, Loc,
-                   AvailabilitySet(SpecialCXXMethod), Comment, Declaration,
-                   SubHeading, Signature, SpecialCXXMethod->isStatic(), Access,
-                   isInSystemHeader(SpecialCXXMethod));
-}
-
-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;
-    }
-
-    if (isa<CXXConversionDecl>(Method)) {
-      recordConversionMethod(CXXClassRecord, Method);
-      continue;
-    }
-
-    if (Method->isFunctionTemplateSpecialization())
-      return;
-
-    StringRef Name;
-    DeclarationFragments Declaration;
-    if (Method->isOverloadedOperator()) {
-      Name = API.copyString(Method->getNameAsString());
-      Declaration =
-          DeclarationFragmentsBuilder::getFragmentsForOverloadedOperator(
-              Method);
-    } else {
-      Name = API.copyString(Method->getNameAsString());
-      Declaration =
-          DeclarationFragmentsBuilder::getFragmentsForCXXMethod(Method);
-    }
-    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 SubHeading =
-        DeclarationFragmentsBuilder::getSubHeading(Method);
-    FunctionSignature Signature =
-        DeclarationFragmentsBuilder::getFunctionSignature(Method);
-    AccessControl Access =
-        DeclarationFragmentsBuilder::getAccessControl(Method);
+      DeclarationFragmentsBuilder::getFunctionSignature(Decl);
+  AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl);
 
-    API.addCXXMethod(CXXClassRecord, Name, USR, Loc, AvailabilitySet(Method),
-                     Comment, Declaration, SubHeading, Signature,
-                     Method->isStatic(), Access, isInSystemHeader(Method));
-  }
+  SmallString<128> ParentUSR;
+  index::generateUSRForDecl(dyn_cast<CXXRecordDecl>(Decl->getDeclContext()),
+                            ParentUSR);
+  if (Decl->isStatic())
+    API.addCXXStaticMethod(API.findRecordForUSR(ParentUSR), Name, USR, Loc,
+                           AvailabilitySet(Decl), Comment, Declaration,
+                           SubHeading, Signature, Access,
+                           isInSystemHeader(Decl));
+  else
+    API.addCXXInstanceMethod(API.findRecordForUSR(ParentUSR), Name, USR, Loc,
+                             AvailabilitySet(Decl), Comment, Declaration,
+                             SubHeading, Signature, Access,
+                             isInSystemHeader(Decl));
+  return true;
 }
 
 /// Collect API information for the Objective-C methods and associate with the

diff  --git a/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h b/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
index 34bb83a1382339..269333245c8363 100644
--- a/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
+++ b/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
@@ -39,10 +39,16 @@ template <typename Derived> class APISetVisitor {
 
     getDerived()->traverseClassTemplatePartialSpecializationRecords();
 
+    getDerived()->traverseCXXInstanceMethods();
+
+    getDerived()->traverseCXXStaticMethods();
+
     getDerived()->traverseCXXMethodTemplates();
 
     getDerived()->traverseCXXMethodTemplateSpecializations();
 
+    getDerived()->traverseCXXFields();
+
     getDerived()->traverseCXXFieldTemplates();
 
     getDerived()->traverseConcepts();
@@ -131,6 +137,21 @@ template <typename Derived> class APISetVisitor {
           *ClassTemplatePartialSpecialization.second);
   }
 
+  void traverseCXXInstanceMethods() {
+    for (const auto &InstanceMethod : API.getCXXInstanceMethods())
+      getDerived()->visitCXXInstanceMethodRecord(*InstanceMethod.second);
+  }
+
+  void traverseCXXStaticMethods() {
+    for (const auto &InstanceMethod : API.getCXXStaticMethods())
+      getDerived()->visitCXXStaticMethodRecord(*InstanceMethod.second);
+  }
+
+  void traverseCXXFields() {
+    for (const auto &CXXField : API.getCXXFields())
+      getDerived()->visitCXXFieldRecord(*CXXField.second);
+  }
+
   void traverseCXXFieldTemplates() {
     for (const auto &CXXFieldTemplate : API.getCXXFieldTemplates())
       getDerived()->visitCXXFieldTemplateRecord(*CXXFieldTemplate.second);
@@ -223,6 +244,10 @@ template <typename Derived> class APISetVisitor {
   void visitClassTemplatePartialSpecializationRecord(
       const ClassTemplatePartialSpecializationRecord &Record){};
 
+  void visitCXXInstanceRecord(const CXXInstanceMethodRecord &Record){};
+
+  void visitCXXStaticRecord(const CXXStaticMethodRecord &Record){};
+
   void visitMethodTemplateRecord(const CXXMethodTemplateRecord &Record){};
 
   void visitMethodTemplateSpecializationRecord(

diff  --git a/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h b/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
index ca12c8f7a9b013..05cc33a0cb8c08 100644
--- a/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
+++ b/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
@@ -183,11 +183,17 @@ class SymbolGraphSerializer : public APISetVisitor<SymbolGraphSerializer> {
   void visitClassTemplatePartialSpecializationRecord(
       const ClassTemplatePartialSpecializationRecord &Record);
 
+  void visitCXXInstanceMethodRecord(const CXXInstanceMethodRecord &Record);
+
+  void visitCXXStaticMethodRecord(const CXXStaticMethodRecord &Record);
+
   void visitMethodTemplateRecord(const CXXMethodTemplateRecord &Record);
 
   void visitMethodTemplateSpecializationRecord(
       const CXXMethodTemplateSpecializationRecord &Record);
 
+  void visitCXXFieldRecord(const CXXFieldRecord &Record);
+
   void visitCXXFieldTemplateRecord(const CXXFieldTemplateRecord &Record);
 
   void visitConceptRecord(const ConceptRecord &Record);

diff  --git a/clang/lib/ExtractAPI/API.cpp b/clang/lib/ExtractAPI/API.cpp
index 6cc00bc939c79c..9e4cfe6dbab308 100644
--- a/clang/lib/ExtractAPI/API.cpp
+++ b/clang/lib/ExtractAPI/API.cpp
@@ -171,18 +171,17 @@ APISet::addStaticField(StringRef Name, StringRef USR, PresumedLoc Loc,
 }
 
 CXXFieldRecord *
-APISet::addCXXField(CXXClassRecord *CXXClass, StringRef Name, StringRef USR,
+APISet::addCXXField(APIRecord *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);
+  auto *Record = addTopLevelRecord(
+      USRBasedLookupTable, CXXFields, 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();
+  return Record;
 }
 
 CXXFieldTemplateRecord *APISet::addCXXFieldTemplate(
@@ -280,50 +279,38 @@ ConceptRecord *APISet::addConcept(StringRef Name, StringRef USR,
                            SubHeading, Template, IsFromSystemHeader);
 }
 
-CXXMethodRecord *APISet::addCXXMethod(
-    CXXClassRecord *CXXClassRecord, StringRef Name, StringRef USR,
-    PresumedLoc Loc, AvailabilitySet Availability, const DocComment &Comment,
+CXXMethodRecord *APISet::addCXXInstanceMethod(
+    APIRecord *CXXClassRecord, StringRef Name, StringRef USR, PresumedLoc Loc,
+    AvailabilitySet Availability, const DocComment &Comment,
     DeclarationFragments Declaration, DeclarationFragments SubHeading,
-    FunctionSignature Signature, bool IsStatic, AccessControl Access,
+    FunctionSignature Signature, 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);
+  CXXMethodRecord *Record =
+      addTopLevelRecord(USRBasedLookupTable, CXXInstanceMethods, 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();
+  return Record;
 }
 
-CXXMethodRecord *APISet::addCXXSpecialMethod(
-    CXXClassRecord *CXXClassRecord, StringRef Name, StringRef USR,
-    PresumedLoc Loc, AvailabilitySet Availability, const DocComment &Comment,
+CXXMethodRecord *APISet::addCXXStaticMethod(
+    APIRecord *CXXClassRecord, StringRef Name, StringRef USR, PresumedLoc Loc,
+    AvailabilitySet Availability, const DocComment &Comment,
     DeclarationFragments Declaration, DeclarationFragments SubHeading,
-    FunctionSignature Signature, bool IsConstructor, AccessControl Access,
+    FunctionSignature Signature, 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);
+  CXXMethodRecord *Record =
+      addTopLevelRecord(USRBasedLookupTable, CXXStaticMethods, 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();
+  return Record;
 }
 
 CXXMethodTemplateRecord *APISet::addCXXMethodTemplate(

diff  --git a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
index 6782483681a0b1..e1b5f652764f11 100644
--- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
+++ b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
@@ -885,9 +885,6 @@ void SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord &Record) {
     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);
 }
@@ -899,9 +896,6 @@ void SymbolGraphSerializer::visitClassTemplateRecord(
     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);
 }
@@ -913,8 +907,6 @@ void SymbolGraphSerializer::visitClassTemplateSpecializationRecord(
     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);
@@ -927,13 +919,33 @@ void SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord(
     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::visitCXXInstanceMethodRecord(
+    const CXXInstanceMethodRecord &Record) {
+  auto InstanceMethod = serializeAPIRecord(Record);
+  if (!InstanceMethod)
+    return;
+
+  Symbols.emplace_back(std::move(*InstanceMethod));
+  serializeRelationship(RelationshipKind::MemberOf, Record,
+                        Record.ParentInformation.ParentRecord);
+}
+
+void SymbolGraphSerializer::visitCXXStaticMethodRecord(
+    const CXXStaticMethodRecord &Record) {
+  auto StaticMethod = serializeAPIRecord(Record);
+  if (!StaticMethod)
+    return;
+
+  Symbols.emplace_back(std::move(*StaticMethod));
+  serializeRelationship(RelationshipKind::MemberOf, Record,
+                        Record.ParentInformation.ParentRecord);
+}
+
 void SymbolGraphSerializer::visitMethodTemplateRecord(
     const CXXMethodTemplateRecord &Record) {
   if (!ShouldRecurse)
@@ -960,6 +972,17 @@ void SymbolGraphSerializer::visitMethodTemplateSpecializationRecord(
                         Record.ParentInformation.ParentRecord);
 }
 
+void SymbolGraphSerializer::visitCXXFieldRecord(const CXXFieldRecord &Record) {
+  if (!ShouldRecurse)
+    return;
+  auto CXXField = serializeAPIRecord(Record);
+  if (!CXXField)
+    return;
+  Symbols.emplace_back(std::move(*CXXField));
+  serializeRelationship(RelationshipKind::MemberOf, Record,
+                        Record.ParentInformation.ParentRecord);
+}
+
 void SymbolGraphSerializer::visitCXXFieldTemplateRecord(
     const CXXFieldTemplateRecord &Record) {
   if (!ShouldRecurse)

diff  --git a/clang/test/ExtractAPI/constructor_destructor.cpp b/clang/test/ExtractAPI/constructor_destructor.cpp
index 63048d1a4baed6..65a924b53d69cb 100644
--- a/clang/test/ExtractAPI/constructor_destructor.cpp
+++ b/clang/test/ExtractAPI/constructor_destructor.cpp
@@ -137,7 +137,7 @@ class Foo {
         "precise": "c:@S at Foo@F at Foo#"
       },
       "kind": {
-        "displayName": "Constructor",
+        "displayName": "Instance Method",
         "identifier": "c++.method"
       },
       "location": {
@@ -193,7 +193,7 @@ class Foo {
         "precise": "c:@S at Foo@F@~Foo#"
       },
       "kind": {
-        "displayName": "Destructor",
+        "displayName": "Instance Method",
         "identifier": "c++.method"
       },
       "location": {

diff  --git a/clang/test/ExtractAPI/methods.cpp b/clang/test/ExtractAPI/methods.cpp
index aed21c6afba82e..f25f9ecf0605c0 100644
--- a/clang/test/ExtractAPI/methods.cpp
+++ b/clang/test/ExtractAPI/methods.cpp
@@ -64,13 +64,13 @@ class Foo {
     },
     {
       "kind": "memberOf",
-      "source": "c:@S at Foo@F at getFoo#S",
+      "source": "c:@S at Foo@F at getBar#1",
       "target": "c:@S at Foo",
       "targetFallback": "Foo"
     },
     {
       "kind": "memberOf",
-      "source": "c:@S at Foo@F at getBar#1",
+      "source": "c:@S at Foo@F at getFoo#S",
       "target": "c:@S at Foo",
       "targetFallback": "Foo"
     }
@@ -310,11 +310,11 @@ class Foo {
       ]
     },
     {
-      "accessLevel": "public",
+      "accessLevel": "protected",
       "declarationFragments": [
         {
           "kind": "keyword",
-          "spelling": "static"
+          "spelling": "constexpr"
         },
         {
           "kind": "text",
@@ -322,8 +322,8 @@ class Foo {
         },
         {
           "kind": "typeIdentifier",
-          "preciseIdentifier": "c:d",
-          "spelling": "double"
+          "preciseIdentifier": "c:I",
+          "spelling": "int"
         },
         {
           "kind": "text",
@@ -331,34 +331,42 @@ class Foo {
         },
         {
           "kind": "identifier",
-          "spelling": "getFoo"
+          "spelling": "getBar"
         },
         {
           "kind": "text",
-          "spelling": "();"
+          "spelling": "() "
+        },
+        {
+          "kind": "keyword",
+          "spelling": "const"
+        },
+        {
+          "kind": "text",
+          "spelling": ";"
         }
       ],
       "functionSignature": {
         "returns": [
           {
             "kind": "typeIdentifier",
-            "preciseIdentifier": "c:d",
-            "spelling": "double"
+            "preciseIdentifier": "c:I",
+            "spelling": "int"
           }
         ]
       },
       "identifier": {
         "interfaceLanguage": "c++",
-        "precise": "c:@S at Foo@F at getFoo#S"
+        "precise": "c:@S at Foo@F at getBar#1"
       },
       "kind": {
-        "displayName": "Static Method",
-        "identifier": "c++.type.method"
+        "displayName": "Instance Method",
+        "identifier": "c++.method"
       },
       "location": {
         "position": {
           "character": 17,
-          "line": 7
+          "line": 10
         },
         "uri": "file://INPUT_DIR/input.h"
       },
@@ -366,28 +374,28 @@ class Foo {
         "navigator": [
           {
             "kind": "identifier",
-            "spelling": "getFoo"
+            "spelling": "getBar"
           }
         ],
         "subHeading": [
           {
             "kind": "identifier",
-            "spelling": "getFoo"
+            "spelling": "getBar"
           }
         ],
-        "title": "getFoo"
+        "title": "getBar"
       },
       "pathComponents": [
         "Foo",
-        "getFoo"
+        "getBar"
       ]
     },
     {
-      "accessLevel": "protected",
+      "accessLevel": "public",
       "declarationFragments": [
         {
           "kind": "keyword",
-          "spelling": "constexpr"
+          "spelling": "static"
         },
         {
           "kind": "text",
@@ -395,8 +403,8 @@ class Foo {
         },
         {
           "kind": "typeIdentifier",
-          "preciseIdentifier": "c:I",
-          "spelling": "int"
+          "preciseIdentifier": "c:d",
+          "spelling": "double"
         },
         {
           "kind": "text",
@@ -404,42 +412,34 @@ class Foo {
         },
         {
           "kind": "identifier",
-          "spelling": "getBar"
-        },
-        {
-          "kind": "text",
-          "spelling": "() "
-        },
-        {
-          "kind": "keyword",
-          "spelling": "const"
+          "spelling": "getFoo"
         },
         {
           "kind": "text",
-          "spelling": ";"
+          "spelling": "();"
         }
       ],
       "functionSignature": {
         "returns": [
           {
             "kind": "typeIdentifier",
-            "preciseIdentifier": "c:I",
-            "spelling": "int"
+            "preciseIdentifier": "c:d",
+            "spelling": "double"
           }
         ]
       },
       "identifier": {
         "interfaceLanguage": "c++",
-        "precise": "c:@S at Foo@F at getBar#1"
+        "precise": "c:@S at Foo@F at getFoo#S"
       },
       "kind": {
-        "displayName": "Instance Method",
-        "identifier": "c++.method"
+        "displayName": "Static Method",
+        "identifier": "c++.type.method"
       },
       "location": {
         "position": {
           "character": 17,
-          "line": 10
+          "line": 7
         },
         "uri": "file://INPUT_DIR/input.h"
       },
@@ -447,20 +447,20 @@ class Foo {
         "navigator": [
           {
             "kind": "identifier",
-            "spelling": "getBar"
+            "spelling": "getFoo"
           }
         ],
         "subHeading": [
           {
             "kind": "identifier",
-            "spelling": "getBar"
+            "spelling": "getFoo"
           }
         ],
-        "title": "getBar"
+        "title": "getFoo"
       },
       "pathComponents": [
         "Foo",
-        "getBar"
+        "getFoo"
       ]
     }
   ]


        


More information about the cfe-commits mailing list