[clang] 3be6c4d - Revert "Revert "Revert ExtractAPI from https://reviews.llvm.org/D146656""

Mitch Phillips via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 29 11:40:11 PDT 2023


Author: Mitch Phillips
Date: 2023-03-29T11:39:44-07:00
New Revision: 3be6c4d413f6ccabdcc8205ce73970bf3df162d3

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

LOG: Revert "Revert "Revert ExtractAPI from https://reviews.llvm.org/D146656""

This reverts commit 79116475124112051625b1a0665e35c861bb13fd.

Broke the ASan bots. See more information in
https://reviews.llvm.org/rG79116475124112051625b1a0665e35c861bb13fd

Added: 
    clang/lib/ExtractAPI/ExtractAPIVisitor.cpp
    clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.h

Modified: 
    clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
    clang/lib/ExtractAPI/CMakeLists.txt
    clang/lib/ExtractAPI/DeclarationFragments.cpp
    clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
    clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp
    clang/test/Index/extract-api-cursor.m
    clang/tools/c-index-test/c-index-test.c
    clang/tools/libclang/CXExtractAPI.cpp

Removed: 
    clang/include/clang/ExtractAPI/TypedefUnderlyingTypeResolver.h


################################################################################
diff  --git a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
index a31648b80195a..f6546fb4776a6 100644
--- a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
+++ b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
@@ -14,27 +14,24 @@
 #ifndef LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H
 #define LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H
 
-#include "llvm/ADT/FunctionExtras.h"
-
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/ParentMapContext.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/ExtractAPI/API.h"
-#include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h"
-#include <type_traits>
+#include "llvm/ADT/FunctionExtras.h"
 
 namespace clang {
 namespace extractapi {
-namespace impl {
-
-template <typename Derived>
-class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
-protected:
-  ExtractAPIVisitorBase(ASTContext &Context, APISet &API)
-      : Context(Context), API(API) {}
 
+/// The RecursiveASTVisitor to traverse symbol declarations and collect API
+/// information.
+class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
 public:
+  ExtractAPIVisitor(ASTContext &Context,
+                    llvm::unique_function<bool(SourceLocation)> LocationChecker,
+                    APISet &API)
+      : Context(Context), API(API),
+        LocationChecker(std::move(LocationChecker)) {}
+
   const APISet &getAPI() const { return API; }
 
   bool VisitVarDecl(const VarDecl *Decl);
@@ -53,11 +50,7 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
 
   bool VisitObjCCategoryDecl(const ObjCCategoryDecl *Decl);
 
-  bool shouldDeclBeIncluded(const Decl *Decl) const;
-
-  const RawComment *fetchRawCommentForDecl(const Decl *Decl) const;
-
-protected:
+private:
   /// Collect API information for the enum constants and associate with the
   /// parent enum.
   void recordEnumConstants(EnumRecord *EnumRecord,
@@ -84,582 +77,9 @@ class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
 
   void recordObjCProtocols(ObjCContainerRecord *Container,
                            ObjCInterfaceDecl::protocol_range Protocols);
-
   ASTContext &Context;
   APISet &API;
-
-  StringRef getTypedefName(const TagDecl *Decl) {
-    if (const auto *TypedefDecl = Decl->getTypedefNameForAnonDecl())
-      return TypedefDecl->getName();
-
-    return {};
-  }
-
-  bool isInSystemHeader(const Decl *D) {
-    return Context.getSourceManager().isInSystemHeader(D->getLocation());
-  }
-
-private:
-  Derived &getDerivedExtractAPIVisitor() {
-    return *static_cast<Derived *>(this);
-  }
-};
-
-template <typename Derived>
-bool ExtractAPIVisitorBase<Derived>::VisitVarDecl(const VarDecl *Decl) {
-  // skip function parameters.
-  if (isa<ParmVarDecl>(Decl))
-    return true;
-
-  // Skip non-global variables in records (struct/union/class).
-  if (Decl->getDeclContext()->isRecord())
-    return true;
-
-  // Skip local variables inside function or method.
-  if (!Decl->isDefinedOutsideFunctionOrMethod())
-    return true;
-
-  // If this is a template but not specialization or instantiation, skip.
-  if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) &&
-      Decl->getTemplateSpecializationKind() == TSK_Undeclared)
-    return true;
-
-  if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
-    return true;
-
-  // Collect symbol information.
-  StringRef Name = Decl->getName();
-  StringRef USR = API.recordUSR(Decl);
-  PresumedLoc Loc =
-      Context.getSourceManager().getPresumedLoc(Decl->getLocation());
-  LinkageInfo Linkage = Decl->getLinkageAndVisibility();
-  DocComment Comment;
-  if (auto *RawComment =
-          getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
-    Comment = RawComment->getFormattedLines(Context.getSourceManager(),
-                                            Context.getDiagnostics());
-
-  // Build declaration fragments and sub-heading for the variable.
-  DeclarationFragments Declaration =
-      DeclarationFragmentsBuilder::getFragmentsForVar(Decl);
-  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));
-  return true;
-}
-
-template <typename Derived>
-bool ExtractAPIVisitorBase<Derived>::VisitFunctionDecl(
-    const FunctionDecl *Decl) {
-  if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
-    // Skip member function in class templates.
-    if (Method->getParent()->getDescribedClassTemplate() != nullptr)
-      return true;
-
-    // Skip methods in records.
-    for (auto P : Context.getParents(*Method)) {
-      if (P.template get<CXXRecordDecl>())
-        return true;
-    }
-
-    // Skip ConstructorDecl and DestructorDecl.
-    if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method))
-      return true;
-  }
-
-  // Skip templated functions.
-  switch (Decl->getTemplatedKind()) {
-  case FunctionDecl::TK_NonTemplate:
-  case FunctionDecl::TK_DependentNonTemplate:
-    break;
-  case FunctionDecl::TK_MemberSpecialization:
-  case FunctionDecl::TK_FunctionTemplateSpecialization:
-    if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) {
-      if (!TemplateInfo->isExplicitInstantiationOrSpecialization())
-        return true;
-    }
-    break;
-  case FunctionDecl::TK_FunctionTemplate:
-  case FunctionDecl::TK_DependentFunctionTemplateSpecialization:
-    return true;
-  }
-
-  if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
-    return true;
-
-  // Collect symbol information.
-  StringRef Name = Decl->getName();
-  StringRef USR = API.recordUSR(Decl);
-  PresumedLoc Loc =
-      Context.getSourceManager().getPresumedLoc(Decl->getLocation());
-  LinkageInfo Linkage = Decl->getLinkageAndVisibility();
-  DocComment Comment;
-  if (auto *RawComment =
-          getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
-    Comment = RawComment->getFormattedLines(Context.getSourceManager(),
-                                            Context.getDiagnostics());
-
-  // Build declaration fragments, sub-heading, and signature of the function.
-  DeclarationFragments Declaration =
-      DeclarationFragmentsBuilder::getFragmentsForFunction(Decl);
-  DeclarationFragments SubHeading =
-      DeclarationFragmentsBuilder::getSubHeading(Decl);
-  FunctionSignature Signature =
-      DeclarationFragmentsBuilder::getFunctionSignature(Decl);
-
-  // Add the function record to the API set.
-  API.addGlobalFunction(Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment,
-                        Declaration, SubHeading, Signature,
-                        isInSystemHeader(Decl));
-  return true;
-}
-
-template <typename Derived>
-bool ExtractAPIVisitorBase<Derived>::VisitEnumDecl(const EnumDecl *Decl) {
-  if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
-    return true;
-
-  SmallString<128> QualifiedNameBuffer;
-  // Collect symbol information.
-  StringRef Name = Decl->getName();
-  if (Name.empty())
-    Name = getTypedefName(Decl);
-  if (Name.empty()) {
-    llvm::raw_svector_ostream OS(QualifiedNameBuffer);
-    Decl->printQualifiedName(OS);
-    Name = QualifiedNameBuffer.str();
-  }
-
-  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 and sub-heading for the enum.
-  DeclarationFragments Declaration =
-      DeclarationFragmentsBuilder::getFragmentsForEnum(Decl);
-  DeclarationFragments SubHeading =
-      DeclarationFragmentsBuilder::getSubHeading(Decl);
-
-  EnumRecord *EnumRecord =
-      API.addEnum(API.copyString(Name), USR, Loc, AvailabilitySet(Decl),
-                  Comment, Declaration, SubHeading, isInSystemHeader(Decl));
-
-  // Now collect information about the enumerators in this enum.
-  getDerivedExtractAPIVisitor().recordEnumConstants(EnumRecord,
-                                                    Decl->enumerators());
-
-  return true;
-}
-
-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;
-
-  if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
-    return true;
-
-  // Collect symbol information.
-  StringRef Name = Decl->getName();
-  if (Name.empty())
-    Name = getTypedefName(Decl);
-  if (Name.empty())
-    return true;
-
-  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 and sub-heading for the struct.
-  DeclarationFragments Declaration =
-      DeclarationFragmentsBuilder::getFragmentsForStruct(Decl);
-  DeclarationFragments SubHeading =
-      DeclarationFragmentsBuilder::getSubHeading(Decl);
-
-  StructRecord *StructRecord =
-      API.addStruct(Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration,
-                    SubHeading, isInSystemHeader(Decl));
-
-  // Now collect information about the fields in this struct.
-  getDerivedExtractAPIVisitor().recordStructFields(StructRecord,
-                                                   Decl->fields());
-
-  return true;
-}
-
-template <typename Derived>
-bool ExtractAPIVisitorBase<Derived>::VisitObjCInterfaceDecl(
-    const ObjCInterfaceDecl *Decl) {
-  if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
-    return true;
-
-  // Collect symbol information.
-  StringRef Name = Decl->getName();
-  StringRef USR = API.recordUSR(Decl);
-  PresumedLoc Loc =
-      Context.getSourceManager().getPresumedLoc(Decl->getLocation());
-  LinkageInfo Linkage = Decl->getLinkageAndVisibility();
-  DocComment Comment;
-  if (auto *RawComment =
-          getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
-    Comment = RawComment->getFormattedLines(Context.getSourceManager(),
-                                            Context.getDiagnostics());
-
-  // Build declaration fragments and sub-heading for the interface.
-  DeclarationFragments Declaration =
-      DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl);
-  DeclarationFragments SubHeading =
-      DeclarationFragmentsBuilder::getSubHeading(Decl);
-
-  // Collect super class information.
-  SymbolReference SuperClass;
-  if (const auto *SuperClassDecl = Decl->getSuperClass()) {
-    SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString();
-    SuperClass.USR = API.recordUSR(SuperClassDecl);
-  }
-
-  ObjCInterfaceRecord *ObjCInterfaceRecord = API.addObjCInterface(
-      Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment, Declaration,
-      SubHeading, SuperClass, isInSystemHeader(Decl));
-
-  // Record all methods (selectors). This doesn't include automatically
-  // synthesized property methods.
-  getDerivedExtractAPIVisitor().recordObjCMethods(ObjCInterfaceRecord,
-                                                  Decl->methods());
-  getDerivedExtractAPIVisitor().recordObjCProperties(ObjCInterfaceRecord,
-                                                     Decl->properties());
-  getDerivedExtractAPIVisitor().recordObjCInstanceVariables(ObjCInterfaceRecord,
-                                                            Decl->ivars());
-  getDerivedExtractAPIVisitor().recordObjCProtocols(ObjCInterfaceRecord,
-                                                    Decl->protocols());
-
-  return true;
-}
-
-template <typename Derived>
-bool ExtractAPIVisitorBase<Derived>::VisitObjCProtocolDecl(
-    const ObjCProtocolDecl *Decl) {
-  if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(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(Decl))
-    Comment = RawComment->getFormattedLines(Context.getSourceManager(),
-                                            Context.getDiagnostics());
-
-  // Build declaration fragments and sub-heading for the protocol.
-  DeclarationFragments Declaration =
-      DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(Decl);
-  DeclarationFragments SubHeading =
-      DeclarationFragmentsBuilder::getSubHeading(Decl);
-
-  ObjCProtocolRecord *ObjCProtocolRecord =
-      API.addObjCProtocol(Name, USR, Loc, AvailabilitySet(Decl), Comment,
-                          Declaration, SubHeading, isInSystemHeader(Decl));
-
-  getDerivedExtractAPIVisitor().recordObjCMethods(ObjCProtocolRecord,
-                                                  Decl->methods());
-  getDerivedExtractAPIVisitor().recordObjCProperties(ObjCProtocolRecord,
-                                                     Decl->properties());
-  getDerivedExtractAPIVisitor().recordObjCProtocols(ObjCProtocolRecord,
-                                                    Decl->protocols());
-
-  return true;
-}
-
-template <typename Derived>
-bool ExtractAPIVisitorBase<Derived>::VisitTypedefNameDecl(
-    const TypedefNameDecl *Decl) {
-  // Skip ObjC Type Parameter for now.
-  if (isa<ObjCTypeParamDecl>(Decl))
-    return true;
-
-  if (!Decl->isDefinedOutsideFunctionOrMethod())
-    return true;
-
-  if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl))
-    return true;
-
-  PresumedLoc Loc =
-      Context.getSourceManager().getPresumedLoc(Decl->getLocation());
-  StringRef Name = Decl->getName();
-  StringRef USR = API.recordUSR(Decl);
-  DocComment Comment;
-  if (auto *RawComment =
-          getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl))
-    Comment = RawComment->getFormattedLines(Context.getSourceManager(),
-                                            Context.getDiagnostics());
-
-  QualType Type = Decl->getUnderlyingType();
-  SymbolReference SymRef =
-      TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type,
-                                                                       API);
-
-  API.addTypedef(Name, USR, Loc, AvailabilitySet(Decl), Comment,
-                 DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl),
-                 DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef,
-                 isInSystemHeader(Decl));
-
-  return true;
-}
-
-template <typename Derived>
-bool ExtractAPIVisitorBase<Derived>::VisitObjCCategoryDecl(
-    const ObjCCategoryDecl *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());
-  // Build declaration fragments and sub-heading for the category.
-  DeclarationFragments Declaration =
-      DeclarationFragmentsBuilder::getFragmentsForObjCCategory(Decl);
-  DeclarationFragments SubHeading =
-      DeclarationFragmentsBuilder::getSubHeading(Decl);
-
-  const ObjCInterfaceDecl *InterfaceDecl = Decl->getClassInterface();
-  SymbolReference Interface(InterfaceDecl->getName(),
-                            API.recordUSR(InterfaceDecl));
-
-  ObjCCategoryRecord *ObjCCategoryRecord = API.addObjCCategory(
-      Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration, SubHeading,
-      Interface, isInSystemHeader(Decl));
-
-  getDerivedExtractAPIVisitor().recordObjCMethods(ObjCCategoryRecord,
-                                                  Decl->methods());
-  getDerivedExtractAPIVisitor().recordObjCProperties(ObjCCategoryRecord,
-                                                     Decl->properties());
-  getDerivedExtractAPIVisitor().recordObjCInstanceVariables(ObjCCategoryRecord,
-                                                            Decl->ivars());
-  getDerivedExtractAPIVisitor().recordObjCProtocols(ObjCCategoryRecord,
-                                                    Decl->protocols());
-
-  return true;
-}
-
-/// Collect API information for the enum constants and associate with the
-/// parent enum.
-template <typename Derived>
-void ExtractAPIVisitorBase<Derived>::recordEnumConstants(
-    EnumRecord *EnumRecord, const EnumDecl::enumerator_range Constants) {
-  for (const auto *Constant : Constants) {
-    // Collect symbol information.
-    StringRef Name = Constant->getName();
-    StringRef USR = API.recordUSR(Constant);
-    PresumedLoc Loc =
-        Context.getSourceManager().getPresumedLoc(Constant->getLocation());
-    DocComment Comment;
-    if (auto *RawComment =
-            getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Constant))
-      Comment = RawComment->getFormattedLines(Context.getSourceManager(),
-                                              Context.getDiagnostics());
-
-    // Build declaration fragments and sub-heading for the enum constant.
-    DeclarationFragments Declaration =
-        DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant);
-    DeclarationFragments SubHeading =
-        DeclarationFragmentsBuilder::getSubHeading(Constant);
-
-    API.addEnumConstant(EnumRecord, Name, USR, Loc, AvailabilitySet(Constant),
-                        Comment, Declaration, SubHeading,
-                        isInSystemHeader(Constant));
-  }
-}
-
-/// Collect API information for the struct fields and associate with the
-/// parent struct.
-template <typename Derived>
-void ExtractAPIVisitorBase<Derived>::recordStructFields(
-    StructRecord *StructRecord, 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());
-    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);
-
-    API.addStructField(StructRecord, Name, USR, Loc, AvailabilitySet(Field),
-                       Comment, Declaration, SubHeading,
-                       isInSystemHeader(Field));
-  }
-}
-
-/// Collect API information for the Objective-C methods and associate with the
-/// parent container.
-template <typename Derived>
-void ExtractAPIVisitorBase<Derived>::recordObjCMethods(
-    ObjCContainerRecord *Container,
-    const ObjCContainerDecl::method_range Methods) {
-  for (const auto *Method : Methods) {
-    // Don't record selectors for properties.
-    if (Method->isPropertyAccessor())
-      continue;
-
-    StringRef Name = API.copyString(Method->getSelector().getAsString());
-    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::getFragmentsForObjCMethod(Method);
-    DeclarationFragments SubHeading =
-        DeclarationFragmentsBuilder::getSubHeading(Method);
-    FunctionSignature Signature =
-        DeclarationFragmentsBuilder::getFunctionSignature(Method);
-
-    API.addObjCMethod(Container, Name, USR, Loc, AvailabilitySet(Method),
-                      Comment, Declaration, SubHeading, Signature,
-                      Method->isInstanceMethod(), isInSystemHeader(Method));
-  }
-}
-
-template <typename Derived>
-void ExtractAPIVisitorBase<Derived>::recordObjCProperties(
-    ObjCContainerRecord *Container,
-    const ObjCContainerDecl::prop_range Properties) {
-  for (const auto *Property : Properties) {
-    StringRef Name = Property->getName();
-    StringRef USR = API.recordUSR(Property);
-    PresumedLoc Loc =
-        Context.getSourceManager().getPresumedLoc(Property->getLocation());
-    DocComment Comment;
-    if (auto *RawComment =
-            getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Property))
-      Comment = RawComment->getFormattedLines(Context.getSourceManager(),
-                                              Context.getDiagnostics());
-
-    // Build declaration fragments and sub-heading for the property.
-    DeclarationFragments Declaration =
-        DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property);
-    DeclarationFragments SubHeading =
-        DeclarationFragmentsBuilder::getSubHeading(Property);
-
-    StringRef GetterName =
-        API.copyString(Property->getGetterName().getAsString());
-    StringRef SetterName =
-        API.copyString(Property->getSetterName().getAsString());
-
-    // Get the attributes for property.
-    unsigned Attributes = ObjCPropertyRecord::NoAttr;
-    if (Property->getPropertyAttributes() &
-        ObjCPropertyAttribute::kind_readonly)
-      Attributes |= ObjCPropertyRecord::ReadOnly;
-
-    API.addObjCProperty(
-        Container, Name, USR, Loc, AvailabilitySet(Property), Comment,
-        Declaration, SubHeading,
-        static_cast<ObjCPropertyRecord::AttributeKind>(Attributes), GetterName,
-        SetterName, Property->isOptional(),
-        !(Property->getPropertyAttributes() &
-          ObjCPropertyAttribute::kind_class),
-        isInSystemHeader(Property));
-  }
-}
-
-template <typename Derived>
-void ExtractAPIVisitorBase<Derived>::recordObjCInstanceVariables(
-    ObjCContainerRecord *Container,
-    const llvm::iterator_range<
-        DeclContext::specific_decl_iterator<ObjCIvarDecl>>
-        Ivars) {
-  for (const auto *Ivar : Ivars) {
-    StringRef Name = Ivar->getName();
-    StringRef USR = API.recordUSR(Ivar);
-    PresumedLoc Loc =
-        Context.getSourceManager().getPresumedLoc(Ivar->getLocation());
-    DocComment Comment;
-    if (auto *RawComment =
-            getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Ivar))
-      Comment = RawComment->getFormattedLines(Context.getSourceManager(),
-                                              Context.getDiagnostics());
-
-    // Build declaration fragments and sub-heading for the instance variable.
-    DeclarationFragments Declaration =
-        DeclarationFragmentsBuilder::getFragmentsForField(Ivar);
-    DeclarationFragments SubHeading =
-        DeclarationFragmentsBuilder::getSubHeading(Ivar);
-
-    ObjCInstanceVariableRecord::AccessControl Access =
-        Ivar->getCanonicalAccessControl();
-
-    API.addObjCInstanceVariable(Container, Name, USR, Loc,
-                                AvailabilitySet(Ivar), Comment, Declaration,
-                                SubHeading, Access, isInSystemHeader(Ivar));
-  }
-}
-
-template <typename Derived>
-void ExtractAPIVisitorBase<Derived>::recordObjCProtocols(
-    ObjCContainerRecord *Container,
-    ObjCInterfaceDecl::protocol_range Protocols) {
-  for (const auto *Protocol : Protocols)
-    Container->Protocols.emplace_back(Protocol->getName(),
-                                      API.recordUSR(Protocol));
-}
-
-} // namespace impl
-
-/// The RecursiveASTVisitor to traverse symbol declarations and collect API
-/// information.
-template <typename Derived = void>
-class ExtractAPIVisitor
-    : public impl::ExtractAPIVisitorBase<std::conditional_t<
-          std::is_same_v<Derived, void>, ExtractAPIVisitor<>, Derived>> {
-  using Base = impl::ExtractAPIVisitorBase<std::conditional_t<
-      std::is_same_v<Derived, void>, ExtractAPIVisitor<>, Derived>>;
-
-public:
-  ExtractAPIVisitor(ASTContext &Context, APISet &API) : Base(Context, API) {}
-
-  bool shouldDeclBeIncluded(const Decl *D) const { return true; }
-  const RawComment *fetchRawCommentForDecl(const Decl *D) const {
-    return this->Context.getRawCommentForDeclNoCache(D);
-  }
+  llvm::unique_function<bool(SourceLocation)> LocationChecker;
 };
 
 } // namespace extractapi

diff  --git a/clang/lib/ExtractAPI/CMakeLists.txt b/clang/lib/ExtractAPI/CMakeLists.txt
index 153d4b992fda7..80fafcd6a0196 100644
--- a/clang/lib/ExtractAPI/CMakeLists.txt
+++ b/clang/lib/ExtractAPI/CMakeLists.txt
@@ -8,6 +8,7 @@ add_clang_library(clangExtractAPI
   APIIgnoresList.cpp
   AvailabilityInfo.cpp
   ExtractAPIConsumer.cpp
+  ExtractAPIVisitor.cpp
   DeclarationFragments.cpp
   Serialization/SerializerBase.cpp
   Serialization/SymbolGraphSerializer.cpp

diff  --git a/clang/lib/ExtractAPI/DeclarationFragments.cpp b/clang/lib/ExtractAPI/DeclarationFragments.cpp
index 675d4e8dc8638..c42a1de2fd358 100644
--- a/clang/lib/ExtractAPI/DeclarationFragments.cpp
+++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp
@@ -12,7 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/ExtractAPI/DeclarationFragments.h"
-#include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h"
+#include "TypedefUnderlyingTypeResolver.h"
 #include "clang/Index/USRGeneration.h"
 #include "llvm/ADT/StringSwitch.h"
 

diff  --git a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
index c27b2d025374a..c1e47b10a39fe 100644
--- a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
+++ b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
@@ -12,10 +12,8 @@
 ///
 //===----------------------------------------------------------------------===//
 
-#include "clang/AST/ASTConcept.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclObjC.h"
 #include "clang/Basic/DiagnosticFrontend.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
@@ -35,7 +33,6 @@
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
-#include "llvm/Support/Casting.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/MemoryBuffer.h"
@@ -222,34 +219,11 @@ struct LocationFileChecker {
   llvm::DenseSet<const FileEntry *> ExternalFileEntries;
 };
 
-struct BatchExtractAPIVisitor : ExtractAPIVisitor<BatchExtractAPIVisitor> {
-  bool shouldDeclBeIncluded(const Decl *D) const {
-    bool ShouldBeIncluded = true;
-    // Check that we have the definition for redeclarable types.
-    if (auto *TD = llvm::dyn_cast<TagDecl>(D))
-      ShouldBeIncluded = TD->isThisDeclarationADefinition();
-    else if (auto *Interface = llvm::dyn_cast<ObjCInterfaceDecl>(D))
-      ShouldBeIncluded = Interface->isThisDeclarationADefinition();
-    else if (auto *Protocol = llvm::dyn_cast<ObjCProtocolDecl>(D))
-      ShouldBeIncluded = Protocol->isThisDeclarationADefinition();
-
-    ShouldBeIncluded = ShouldBeIncluded && LCF(D->getLocation());
-    return ShouldBeIncluded;
-  }
-
-  BatchExtractAPIVisitor(LocationFileChecker &LCF, ASTContext &Context,
-                         APISet &API)
-      : ExtractAPIVisitor<BatchExtractAPIVisitor>(Context, API), LCF(LCF) {}
-
-private:
-  LocationFileChecker &LCF;
-};
-
 class ExtractAPIConsumer : public ASTConsumer {
 public:
   ExtractAPIConsumer(ASTContext &Context,
                      std::unique_ptr<LocationFileChecker> LCF, APISet &API)
-      : Visitor(*LCF, Context, API), LCF(std::move(LCF)) {}
+      : Visitor(Context, *LCF, API), LCF(std::move(LCF)) {}
 
   void HandleTranslationUnit(ASTContext &Context) override {
     // Use ExtractAPIVisitor to traverse symbol declarations in the context.
@@ -257,7 +231,7 @@ class ExtractAPIConsumer : public ASTConsumer {
   }
 
 private:
-  BatchExtractAPIVisitor Visitor;
+  ExtractAPIVisitor Visitor;
   std::unique_ptr<LocationFileChecker> LCF;
 };
 

diff  --git a/clang/lib/ExtractAPI/ExtractAPIVisitor.cpp b/clang/lib/ExtractAPI/ExtractAPIVisitor.cpp
new file mode 100644
index 0000000000000..24260cf89383d
--- /dev/null
+++ b/clang/lib/ExtractAPI/ExtractAPIVisitor.cpp
@@ -0,0 +1,560 @@
+//===- ExtractAPI/ExtractAPIVisitor.cpp -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file implements the ExtractAPIVisitor an ASTVisitor to collect API
+/// information.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/ExtractAPI/ExtractAPIVisitor.h"
+
+#include "TypedefUnderlyingTypeResolver.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ParentMapContext.h"
+#include "clang/AST/RawCommentList.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/ExtractAPI/API.h"
+#include "clang/ExtractAPI/AvailabilityInfo.h"
+#include "clang/ExtractAPI/DeclarationFragments.h"
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Frontend/FrontendOptions.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace extractapi;
+
+namespace {
+
+StringRef getTypedefName(const TagDecl *Decl) {
+  if (const auto *TypedefDecl = Decl->getTypedefNameForAnonDecl())
+    return TypedefDecl->getName();
+
+  return {};
+}
+
+template <class DeclTy>
+bool isInSystemHeader(const ASTContext &Context, const DeclTy *D) {
+  return Context.getSourceManager().isInSystemHeader(D->getLocation());
+}
+
+} // namespace
+
+bool ExtractAPIVisitor::VisitVarDecl(const VarDecl *Decl) {
+  // skip function parameters.
+  if (isa<ParmVarDecl>(Decl))
+    return true;
+
+  // Skip non-global variables in records (struct/union/class).
+  if (Decl->getDeclContext()->isRecord())
+    return true;
+
+  // Skip local variables inside function or method.
+  if (!Decl->isDefinedOutsideFunctionOrMethod())
+    return true;
+
+  // If this is a template but not specialization or instantiation, skip.
+  if (Decl->getASTContext().getTemplateOrSpecializationInfo(Decl) &&
+      Decl->getTemplateSpecializationKind() == TSK_Undeclared)
+    return true;
+
+  if (!LocationChecker(Decl->getLocation()))
+    return true;
+
+  // Collect symbol information.
+  StringRef Name = Decl->getName();
+  StringRef USR = API.recordUSR(Decl);
+  PresumedLoc Loc =
+      Context.getSourceManager().getPresumedLoc(Decl->getLocation());
+  LinkageInfo Linkage = Decl->getLinkageAndVisibility();
+  DocComment Comment;
+  if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
+    Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+                                            Context.getDiagnostics());
+
+  // Build declaration fragments and sub-heading for the variable.
+  DeclarationFragments Declaration =
+      DeclarationFragmentsBuilder::getFragmentsForVar(Decl);
+  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(Context, Decl));
+  return true;
+}
+
+bool ExtractAPIVisitor::VisitFunctionDecl(const FunctionDecl *Decl) {
+  if (const auto *Method = dyn_cast<CXXMethodDecl>(Decl)) {
+    // Skip member function in class templates.
+    if (Method->getParent()->getDescribedClassTemplate() != nullptr)
+      return true;
+
+    // Skip methods in records.
+    for (auto P : Context.getParents(*Method)) {
+      if (P.get<CXXRecordDecl>())
+        return true;
+    }
+
+    // Skip ConstructorDecl and DestructorDecl.
+    if (isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method))
+      return true;
+  }
+
+  // Skip templated functions.
+  switch (Decl->getTemplatedKind()) {
+  case FunctionDecl::TK_NonTemplate:
+  case FunctionDecl::TK_DependentNonTemplate:
+    break;
+  case FunctionDecl::TK_MemberSpecialization:
+  case FunctionDecl::TK_FunctionTemplateSpecialization:
+    if (auto *TemplateInfo = Decl->getTemplateSpecializationInfo()) {
+      if (!TemplateInfo->isExplicitInstantiationOrSpecialization())
+        return true;
+    }
+    break;
+  case FunctionDecl::TK_FunctionTemplate:
+  case FunctionDecl::TK_DependentFunctionTemplateSpecialization:
+    return true;
+  }
+
+  if (!LocationChecker(Decl->getLocation()))
+    return true;
+
+  // Collect symbol information.
+  StringRef Name = Decl->getName();
+  StringRef USR = API.recordUSR(Decl);
+  PresumedLoc Loc =
+      Context.getSourceManager().getPresumedLoc(Decl->getLocation());
+  LinkageInfo Linkage = Decl->getLinkageAndVisibility();
+  DocComment Comment;
+  if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
+    Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+                                            Context.getDiagnostics());
+
+  // Build declaration fragments, sub-heading, and signature of the function.
+  DeclarationFragments Declaration =
+      DeclarationFragmentsBuilder::getFragmentsForFunction(Decl);
+  DeclarationFragments SubHeading =
+      DeclarationFragmentsBuilder::getSubHeading(Decl);
+  FunctionSignature Signature =
+      DeclarationFragmentsBuilder::getFunctionSignature(Decl);
+
+  // Add the function record to the API set.
+  API.addGlobalFunction(Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment,
+                        Declaration, SubHeading, Signature,
+                        isInSystemHeader(Context, Decl));
+  return true;
+}
+
+bool ExtractAPIVisitor::VisitEnumDecl(const EnumDecl *Decl) {
+  if (!Decl->isComplete())
+    return true;
+
+  // Skip forward declaration.
+  if (!Decl->isThisDeclarationADefinition())
+    return true;
+
+  if (!LocationChecker(Decl->getLocation()))
+    return true;
+
+  SmallString<128> QualifiedNameBuffer;
+  // Collect symbol information.
+  StringRef Name = Decl->getName();
+  if (Name.empty())
+    Name = getTypedefName(Decl);
+  if (Name.empty()) {
+    llvm::raw_svector_ostream OS(QualifiedNameBuffer);
+    Decl->printQualifiedName(OS);
+    Name = QualifiedNameBuffer.str();
+  }
+
+  StringRef USR = API.recordUSR(Decl);
+  PresumedLoc Loc =
+      Context.getSourceManager().getPresumedLoc(Decl->getLocation());
+  DocComment Comment;
+  if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
+    Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+                                            Context.getDiagnostics());
+
+  // Build declaration fragments and sub-heading for the enum.
+  DeclarationFragments Declaration =
+      DeclarationFragmentsBuilder::getFragmentsForEnum(Decl);
+  DeclarationFragments SubHeading =
+      DeclarationFragmentsBuilder::getSubHeading(Decl);
+
+  EnumRecord *EnumRecord = API.addEnum(
+      API.copyString(Name), USR, Loc, AvailabilitySet(Decl), Comment,
+      Declaration, SubHeading, isInSystemHeader(Context, Decl));
+
+  // Now collect information about the enumerators in this enum.
+  recordEnumConstants(EnumRecord, Decl->enumerators());
+
+  return true;
+}
+
+bool ExtractAPIVisitor::VisitRecordDecl(const RecordDecl *Decl) {
+  if (!Decl->isCompleteDefinition())
+    return true;
+
+  // Skip C++ structs/classes/unions
+  // TODO: support C++ records
+  if (isa<CXXRecordDecl>(Decl))
+    return true;
+
+  if (!LocationChecker(Decl->getLocation()))
+    return true;
+
+  // Collect symbol information.
+  StringRef Name = Decl->getName();
+  if (Name.empty())
+    Name = getTypedefName(Decl);
+  if (Name.empty())
+    return true;
+
+  StringRef USR = API.recordUSR(Decl);
+  PresumedLoc Loc =
+      Context.getSourceManager().getPresumedLoc(Decl->getLocation());
+  DocComment Comment;
+  if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
+    Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+                                            Context.getDiagnostics());
+
+  // Build declaration fragments and sub-heading for the struct.
+  DeclarationFragments Declaration =
+      DeclarationFragmentsBuilder::getFragmentsForStruct(Decl);
+  DeclarationFragments SubHeading =
+      DeclarationFragmentsBuilder::getSubHeading(Decl);
+
+  StructRecord *StructRecord =
+      API.addStruct(Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration,
+                    SubHeading, isInSystemHeader(Context, Decl));
+
+  // Now collect information about the fields in this struct.
+  recordStructFields(StructRecord, Decl->fields());
+
+  return true;
+}
+
+bool ExtractAPIVisitor::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *Decl) {
+  // Skip forward declaration for classes (@class)
+  if (!Decl->isThisDeclarationADefinition())
+    return true;
+
+  if (!LocationChecker(Decl->getLocation()))
+    return true;
+
+  // Collect symbol information.
+  StringRef Name = Decl->getName();
+  StringRef USR = API.recordUSR(Decl);
+  PresumedLoc Loc =
+      Context.getSourceManager().getPresumedLoc(Decl->getLocation());
+  LinkageInfo Linkage = Decl->getLinkageAndVisibility();
+  DocComment Comment;
+  if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
+    Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+                                            Context.getDiagnostics());
+
+  // Build declaration fragments and sub-heading for the interface.
+  DeclarationFragments Declaration =
+      DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Decl);
+  DeclarationFragments SubHeading =
+      DeclarationFragmentsBuilder::getSubHeading(Decl);
+
+  // Collect super class information.
+  SymbolReference SuperClass;
+  if (const auto *SuperClassDecl = Decl->getSuperClass()) {
+    SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString();
+    SuperClass.USR = API.recordUSR(SuperClassDecl);
+  }
+
+  ObjCInterfaceRecord *ObjCInterfaceRecord = API.addObjCInterface(
+      Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment, Declaration,
+      SubHeading, SuperClass, isInSystemHeader(Context, Decl));
+
+  // Record all methods (selectors). This doesn't include automatically
+  // synthesized property methods.
+  recordObjCMethods(ObjCInterfaceRecord, Decl->methods());
+  recordObjCProperties(ObjCInterfaceRecord, Decl->properties());
+  recordObjCInstanceVariables(ObjCInterfaceRecord, Decl->ivars());
+  recordObjCProtocols(ObjCInterfaceRecord, Decl->protocols());
+
+  return true;
+}
+
+bool ExtractAPIVisitor::VisitObjCProtocolDecl(const ObjCProtocolDecl *Decl) {
+  // Skip forward declaration for protocols (@protocol).
+  if (!Decl->isThisDeclarationADefinition())
+    return true;
+
+  if (!LocationChecker(Decl->getLocation()))
+    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 = Context.getRawCommentForDeclNoCache(Decl))
+    Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+                                            Context.getDiagnostics());
+
+  // Build declaration fragments and sub-heading for the protocol.
+  DeclarationFragments Declaration =
+      DeclarationFragmentsBuilder::getFragmentsForObjCProtocol(Decl);
+  DeclarationFragments SubHeading =
+      DeclarationFragmentsBuilder::getSubHeading(Decl);
+
+  ObjCProtocolRecord *ObjCProtocolRecord = API.addObjCProtocol(
+      Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration, SubHeading,
+      isInSystemHeader(Context, Decl));
+
+  recordObjCMethods(ObjCProtocolRecord, Decl->methods());
+  recordObjCProperties(ObjCProtocolRecord, Decl->properties());
+  recordObjCProtocols(ObjCProtocolRecord, Decl->protocols());
+
+  return true;
+}
+
+bool ExtractAPIVisitor::VisitTypedefNameDecl(const TypedefNameDecl *Decl) {
+  // Skip ObjC Type Parameter for now.
+  if (isa<ObjCTypeParamDecl>(Decl))
+    return true;
+
+  if (!Decl->isDefinedOutsideFunctionOrMethod())
+    return true;
+
+  if (!LocationChecker(Decl->getLocation()))
+    return true;
+
+  PresumedLoc Loc =
+      Context.getSourceManager().getPresumedLoc(Decl->getLocation());
+  StringRef Name = Decl->getName();
+  StringRef USR = API.recordUSR(Decl);
+  DocComment Comment;
+  if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
+    Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+                                            Context.getDiagnostics());
+
+  QualType Type = Decl->getUnderlyingType();
+  SymbolReference SymRef =
+      TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type,
+                                                                       API);
+
+  API.addTypedef(Name, USR, Loc, AvailabilitySet(Decl), Comment,
+                 DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl),
+                 DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef,
+                 isInSystemHeader(Context, Decl));
+
+  return true;
+}
+
+bool ExtractAPIVisitor::VisitObjCCategoryDecl(const ObjCCategoryDecl *Decl) {
+  // Collect symbol information.
+  StringRef Name = Decl->getName();
+  StringRef USR = API.recordUSR(Decl);
+  PresumedLoc Loc =
+      Context.getSourceManager().getPresumedLoc(Decl->getLocation());
+  DocComment Comment;
+  if (auto *RawComment = Context.getRawCommentForDeclNoCache(Decl))
+    Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+                                            Context.getDiagnostics());
+  // Build declaration fragments and sub-heading for the category.
+  DeclarationFragments Declaration =
+      DeclarationFragmentsBuilder::getFragmentsForObjCCategory(Decl);
+  DeclarationFragments SubHeading =
+      DeclarationFragmentsBuilder::getSubHeading(Decl);
+
+  const ObjCInterfaceDecl *InterfaceDecl = Decl->getClassInterface();
+  SymbolReference Interface(InterfaceDecl->getName(),
+                            API.recordUSR(InterfaceDecl));
+
+  ObjCCategoryRecord *ObjCCategoryRecord = API.addObjCCategory(
+      Name, USR, Loc, AvailabilitySet(Decl), Comment, Declaration, SubHeading,
+      Interface, isInSystemHeader(Context, Decl));
+
+  recordObjCMethods(ObjCCategoryRecord, Decl->methods());
+  recordObjCProperties(ObjCCategoryRecord, Decl->properties());
+  recordObjCInstanceVariables(ObjCCategoryRecord, Decl->ivars());
+  recordObjCProtocols(ObjCCategoryRecord, Decl->protocols());
+
+  return true;
+}
+
+/// Collect API information for the enum constants and associate with the
+/// parent enum.
+void ExtractAPIVisitor::recordEnumConstants(
+    EnumRecord *EnumRecord, const EnumDecl::enumerator_range Constants) {
+  for (const auto *Constant : Constants) {
+    // Collect symbol information.
+    StringRef Name = Constant->getName();
+    StringRef USR = API.recordUSR(Constant);
+    PresumedLoc Loc =
+        Context.getSourceManager().getPresumedLoc(Constant->getLocation());
+    DocComment Comment;
+    if (auto *RawComment = Context.getRawCommentForDeclNoCache(Constant))
+      Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+                                              Context.getDiagnostics());
+
+    // Build declaration fragments and sub-heading for the enum constant.
+    DeclarationFragments Declaration =
+        DeclarationFragmentsBuilder::getFragmentsForEnumConstant(Constant);
+    DeclarationFragments SubHeading =
+        DeclarationFragmentsBuilder::getSubHeading(Constant);
+
+    API.addEnumConstant(EnumRecord, Name, USR, Loc, AvailabilitySet(Constant),
+                        Comment, Declaration, SubHeading,
+                        isInSystemHeader(Context, Constant));
+  }
+}
+
+/// Collect API information for the struct fields and associate with the
+/// parent struct.
+void ExtractAPIVisitor::recordStructFields(
+    StructRecord *StructRecord, 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());
+    DocComment Comment;
+    if (auto *RawComment = Context.getRawCommentForDeclNoCache(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);
+
+    API.addStructField(StructRecord, Name, USR, Loc, AvailabilitySet(Field),
+                       Comment, Declaration, SubHeading,
+                       isInSystemHeader(Context, Field));
+  }
+}
+
+/// Collect API information for the Objective-C methods and associate with the
+/// parent container.
+void ExtractAPIVisitor::recordObjCMethods(
+    ObjCContainerRecord *Container,
+    const ObjCContainerDecl::method_range Methods) {
+  for (const auto *Method : Methods) {
+    // Don't record selectors for properties.
+    if (Method->isPropertyAccessor())
+      continue;
+
+    StringRef Name = API.copyString(Method->getSelector().getAsString());
+    StringRef USR = API.recordUSR(Method);
+    PresumedLoc Loc =
+        Context.getSourceManager().getPresumedLoc(Method->getLocation());
+    DocComment Comment;
+    if (auto *RawComment = Context.getRawCommentForDeclNoCache(Method))
+      Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+                                              Context.getDiagnostics());
+
+    // Build declaration fragments, sub-heading, and signature for the method.
+    DeclarationFragments Declaration =
+        DeclarationFragmentsBuilder::getFragmentsForObjCMethod(Method);
+    DeclarationFragments SubHeading =
+        DeclarationFragmentsBuilder::getSubHeading(Method);
+    FunctionSignature Signature =
+        DeclarationFragmentsBuilder::getFunctionSignature(Method);
+
+    API.addObjCMethod(Container, Name, USR, Loc, AvailabilitySet(Method),
+                      Comment, Declaration, SubHeading, Signature,
+                      Method->isInstanceMethod(),
+                      isInSystemHeader(Context, Method));
+  }
+}
+
+void ExtractAPIVisitor::recordObjCProperties(
+    ObjCContainerRecord *Container,
+    const ObjCContainerDecl::prop_range Properties) {
+  for (const auto *Property : Properties) {
+    StringRef Name = Property->getName();
+    StringRef USR = API.recordUSR(Property);
+    PresumedLoc Loc =
+        Context.getSourceManager().getPresumedLoc(Property->getLocation());
+    DocComment Comment;
+    if (auto *RawComment = Context.getRawCommentForDeclNoCache(Property))
+      Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+                                              Context.getDiagnostics());
+
+    // Build declaration fragments and sub-heading for the property.
+    DeclarationFragments Declaration =
+        DeclarationFragmentsBuilder::getFragmentsForObjCProperty(Property);
+    DeclarationFragments SubHeading =
+        DeclarationFragmentsBuilder::getSubHeading(Property);
+
+    StringRef GetterName =
+        API.copyString(Property->getGetterName().getAsString());
+    StringRef SetterName =
+        API.copyString(Property->getSetterName().getAsString());
+
+    // Get the attributes for property.
+    unsigned Attributes = ObjCPropertyRecord::NoAttr;
+    if (Property->getPropertyAttributes() &
+        ObjCPropertyAttribute::kind_readonly)
+      Attributes |= ObjCPropertyRecord::ReadOnly;
+
+    API.addObjCProperty(
+        Container, Name, USR, Loc, AvailabilitySet(Property), Comment,
+        Declaration, SubHeading,
+        static_cast<ObjCPropertyRecord::AttributeKind>(Attributes), GetterName,
+        SetterName, Property->isOptional(),
+        !(Property->getPropertyAttributes() &
+          ObjCPropertyAttribute::kind_class),
+        isInSystemHeader(Context, Property));
+  }
+}
+
+void ExtractAPIVisitor::recordObjCInstanceVariables(
+    ObjCContainerRecord *Container,
+    const llvm::iterator_range<
+        DeclContext::specific_decl_iterator<ObjCIvarDecl>>
+        Ivars) {
+  for (const auto *Ivar : Ivars) {
+    StringRef Name = Ivar->getName();
+    StringRef USR = API.recordUSR(Ivar);
+    PresumedLoc Loc =
+        Context.getSourceManager().getPresumedLoc(Ivar->getLocation());
+    DocComment Comment;
+    if (auto *RawComment = Context.getRawCommentForDeclNoCache(Ivar))
+      Comment = RawComment->getFormattedLines(Context.getSourceManager(),
+                                              Context.getDiagnostics());
+
+    // Build declaration fragments and sub-heading for the instance variable.
+    DeclarationFragments Declaration =
+        DeclarationFragmentsBuilder::getFragmentsForField(Ivar);
+    DeclarationFragments SubHeading =
+        DeclarationFragmentsBuilder::getSubHeading(Ivar);
+
+    ObjCInstanceVariableRecord::AccessControl Access =
+        Ivar->getCanonicalAccessControl();
+
+    API.addObjCInstanceVariable(
+        Container, Name, USR, Loc, AvailabilitySet(Ivar), Comment, Declaration,
+        SubHeading, Access, isInSystemHeader(Context, Ivar));
+  }
+}
+
+void ExtractAPIVisitor::recordObjCProtocols(
+    ObjCContainerRecord *Container,
+    ObjCInterfaceDecl::protocol_range Protocols) {
+  for (const auto *Protocol : Protocols)
+    Container->Protocols.emplace_back(Protocol->getName(),
+                                      API.recordUSR(Protocol));
+}

diff  --git a/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp b/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp
index 3a5f62c9b2e6c..3da2424ea7263 100644
--- a/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp
+++ b/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp
@@ -11,7 +11,7 @@
 ///
 //===----------------------------------------------------------------------===//
 
-#include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h"
+#include "TypedefUnderlyingTypeResolver.h"
 #include "clang/Index/USRGeneration.h"
 
 using namespace clang;

diff  --git a/clang/include/clang/ExtractAPI/TypedefUnderlyingTypeResolver.h b/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.h
similarity index 100%
rename from clang/include/clang/ExtractAPI/TypedefUnderlyingTypeResolver.h
rename to clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.h

diff  --git a/clang/test/Index/extract-api-cursor.m b/clang/test/Index/extract-api-cursor.m
index 16844ca1674ee..078f2f52e215c 100644
--- a/clang/test/Index/extract-api-cursor.m
+++ b/clang/test/Index/extract-api-cursor.m
@@ -1,5 +1,3 @@
-// Test is line- and column-sensitive. Run lines are below
-
 /// Foo docs
 struct Foo {
     /// Bar docs
@@ -27,94 +25,91 @@ @interface Derived: Base
 - (void)derivedMethodWithValue:(id<Protocol>)value;
 @end
 
- at implementation Derived
-- (void)derivedMethodWithValue:(id<Protocol>)value {
-    int a = 5;
-}
+/// This won't show up in docs because we can't serialize it
+ at interface Derived ()
+/// Derived method in category docs, won't show up either.
+- (void)derivedMethodInCategory;
 @end
 
-// RUN: c-index-test -single-symbol-sgf-at=%s:4:9 local %s | FileCheck -check-prefix=CHECK-FOO %s
-// CHECK-FOO: "parentContexts":[]
-// CHECK-FOO: "relatedSymbols":[]
-// CHECK-FOO: "relationships":[]
-// CHECK-FOO: "text":"Foo docs"
-// CHECK-FOO: "kind":{"displayName":"Structure","identifier":"objective-c.struct"}
-// CHECK-FOO: "title":"Foo"
-
-// RUN: c-index-test -single-symbol-sgf-at=%s:6:9 local %s | FileCheck -check-prefix=CHECK-BAR %s
-// CHECK-BAR: "parentContexts":[{"kind":"objective-c.struct","name":"Foo","usr":"c:@S at Foo"}]
-// CHECK-BAR: "relatedSymbols":[]
-// CHECK-BAR: "relationships":[{"kind":"memberOf","source":"c:@S at Foo@FI at bar","target":"c:@S at Foo"
-// CHECK-BAR: "text":"Bar docs"
-// CHECK-BAR: "kind":{"displayName":"Instance Property","identifier":"objective-c.property"}
-// CHECK-BAR: "title":"bar"
-
-// RUN: c-index-test -single-symbol-sgf-at=%s:10:11 local %s | FileCheck -check-prefix=CHECK-BASE %s
-// CHECK-BASE: "parentContexts":[]
-// CHECK-BASE: "relatedSymbols":[]
-// CHECK-BASE: "relationships":[]
-// CHECK-BASE: "text":"Base docs"
-// CHECK-BASE: "kind":{"displayName":"Class","identifier":"objective-c.class"}
-// CHECK-BASE: "title":"Base"
-
-// RUN: c-index-test -single-symbol-sgf-at=%s:12:25 local %s | FileCheck -check-prefix=CHECK-BASE-PROP %s
-// CHECK-BASE-PROP: "parentContexts":[{"kind":"objective-c.class","name":"Base","usr":"c:objc(cs)Base"}]
-// CHECK-BASE-PROP: "relatedSymbols":[{"accessLevel":"public","declarationLanguage":"objective-c"
-// CHECK-BASE-PROP: "isSystem":false
-// CHECK-BASE-PROP: "usr":"c:@S at Foo"}]
-// CHECK-BASE-PROP: "relationships":[{"kind":"memberOf","source":"c:objc(cs)Base(py)baseProperty","target":"c:objc(cs)Base"
-// CHECK-BASE-PROP: "text":"Base property docs"
-// CHECK-BASE-PROP: "kind":{"displayName":"Instance Property","identifier":"objective-c.property"}
-// CHECK-BASE-PROP: "title":"baseProperty"
-
-// RUN: c-index-test -single-symbol-sgf-at=%s:15:9 local %s | FileCheck -check-prefix=CHECK-BASE-METHOD %s
-// CHECK-BASE-METHOD: "parentContexts":[{"kind":"objective-c.class","name":"Base","usr":"c:objc(cs)Base"}]
-// CHECK-BASE-METHOD: "relatedSymbols":[]
-// CHECK-BASE-METHOD: "relationships":[{"kind":"memberOf","source":"c:objc(cs)Base(im)baseMethodWithArg:","target":"c:objc(cs)Base"
-// CHECK-BASE-METHOD: "text":"Base method docs"
-// CHECK-BASE-METHOD: "kind":{"displayName":"Instance Method","identifier":"objective-c.method"}
-// CHECK-BASE-METHOD: "title":"baseMethodWithArg:"
-
-// RUN: c-index-test -single-symbol-sgf-at=%s:19:11 local %s | FileCheck -check-prefix=CHECK-PROTOCOL %s
-// CHECK-PROTOCOL: "parentContexts":[]
-// CHECK-PROTOCOL: "relatedSymbols":[]
-// CHECK-PROTOCOL: "relationships":[]
-// CHECK-PROTOCOL: "text":"Protocol docs"
-// CHECK-PROTOCOL: "kind":{"displayName":"Protocol","identifier":"objective-c.protocol"}
-// CHECK-PROTOCOL: "title":"Protocol"
-
-// RUN: c-index-test -single-symbol-sgf-at=%s:21:27 local %s | FileCheck -check-prefix=CHECK-PROTOCOL-PROP %s
-// CHECK-PROTOCOL-PROP: "parentContexts":[{"kind":"objective-c.protocol","name":"Protocol","usr":"c:objc(pl)Protocol"}]
-// CHECK-PROTOCOL-PROP: "relatedSymbols":[{"accessLevel":"public","declarationLanguage":"objective-c"
-// CHECK-PROTOCOL-PROP: "isSystem":false
-// CHECK-PROTOCOL-PROP: "usr":"c:@S at Foo"}]
-// CHECK-PROTOCOL-PROP: "relationships":[{"kind":"memberOf","source":"c:objc(pl)Protocol(py)protocolProperty","target":"c:objc(pl)Protocol"
-// CHECK-PROTOCOL-PROP: "text":"Protocol property docs"
-// CHECK-PROTOCOL-PROP: "kind":{"displayName":"Instance Property","identifier":"objective-c.property"}
-// CHECK-PROTOCOL-PROP: "title":"protocolProperty"
-
-// RUN: c-index-test -single-symbol-sgf-at=%s:25:15 local %s | FileCheck -check-prefix=CHECK-DERIVED %s
-// CHECK-DERIVED: "parentContexts":[]
-// CHECK-DERIVED: "relatedSymbols":[{"accessLevel":"public","declarationLanguage":"objective-c"
-// CHECK-DERIVED: "isSystem":false
-// CHECK-DERIVED: "usr":"c:objc(cs)Base"}]
-// CHECK-DERIVED: "relationships":[{"kind":"inheritsFrom","source":"c:objc(cs)Derived","target":"c:objc(cs)Base"
-// CHECK-DERIVED: "text":"Derived docs"
-// CHECK-DERIVED: "kind":{"displayName":"Class","identifier":"objective-c.class"}
-// CHECK-DERIVED: "title":"Derived"
-
-// RUN: c-index-test -single-symbol-sgf-at=%s:27:11 local %s | FileCheck -check-prefix=CHECK-DERIVED-METHOD %s
-// CHECK-DERIVED-METHOD: "parentContexts":[{"kind":"objective-c.class","name":"Derived","usr":"c:objc(cs)Derived"}]
-// CHECK-DERIVED-METHOD: "relatedSymbols":[]
-// CHECK-DERIVED-METHOD: "relationships":[{"kind":"memberOf","source":"c:objc(cs)Derived(im)derivedMethodWithValue:","target":"c:objc(cs)Derived"
-// CHECK-DERIVED-METHOD: "text":"Derived method docs"
-// CHECK-DERIVED-METHOD: "kind":{"displayName":"Instance Method","identifier":"objective-c.method"}
-// CHECK-DERIVED-METHOD: "title":"derivedMethodWithValue:"
-
-// RUN: c-index-test -single-symbol-sgf-at=%s:31:11 local %s | FileCheck -check-prefix=CHECK-DERIVED-METHOD-IMPL %s
-// CHECK-DERIVED-METHOD-IMPL: "parentContexts":[{"kind":"objective-c.class","name":"Derived","usr":"c:objc(cs)Derived"}]
-// CHECK-DERIVED-METHOD-IMPL: "relatedSymbols":[]
-// CHECK-DERIVED-METHOD-IMPL: "relationships":[{"kind":"memberOf","source":"c:objc(cs)Derived(im)derivedMethodWithValue:","target":"c:objc(cs)Derived"
-// CHECK-DERIVED-METHOD-IMPL: "text":"Derived method docs"
-// CHECK-DERIVED-METHOD-IMPL: "kind":{"displayName":"Instance Method","identifier":"objective-c.method"}
-// CHECK-DERIVED-METHOD-IMPL: "title":"derivedMethodWithValue:"
+// RUN: c-index-test -single-symbol-sgfs local %s | FileCheck %s
+
+// Checking for Foo
+// CHECK: "parentContexts":[]
+// CHECK-SAME: "relatedSymbols":[]
+// CHECK-SAME: "relationships":[]
+// CHECK-SAME: "text":"Foo docs"
+// CHECK-SAME: "kind":{"displayName":"Structure","identifier":"objective-c.struct"}
+// CHECK-SAME: "title":"Foo"
+
+// Checking for bar
+// CHECK-NEXT: "parentContexts":[{"kind":"objective-c.struct","name":"Foo","usr":"c:@S at Foo"}]
+// CHECK-SAME: "relatedSymbols":[]
+// CHECK-SAME: "relationships":[{"kind":"memberOf","source":"c:@S at Foo@FI at bar","target":"c:@S at Foo"
+// CHECK-SAME: "text":"Bar docs"
+// CHECK-SAME: "kind":{"displayName":"Instance Property","identifier":"objective-c.property"}
+// CHECK-SAME: "title":"bar"
+
+// Checking for Base
+// CHECK-NEXT: "parentContexts":[]
+// CHECK-SAME: "relatedSymbols":[]
+// CHECK-SAME: "relationships":[]
+// CHECK-SAME: "text":"Base docs"
+// CHECK-SAME: "kind":{"displayName":"Class","identifier":"objective-c.class"}
+// CHECK-SAME: "title":"Base"
+
+// Checking for baseProperty
+// CHECK-NEXT: "parentContexts":[{"kind":"objective-c.class","name":"Base","usr":"c:objc(cs)Base"}]
+// CHECK-SAME: "relatedSymbols":[{"accessLevel":"public","declarationLanguage":"objective-c"
+// CHECK-SAME: "isSystem":false
+// CHECK-SAME: "usr":"c:@S at Foo"}]
+// CHECK-SAME: "relationships":[{"kind":"memberOf","source":"c:objc(cs)Base(py)baseProperty","target":"c:objc(cs)Base"
+// CHECK-SAME: "text":"Base property docs"
+// CHECK-SAME: "kind":{"displayName":"Instance Property","identifier":"objective-c.property"}
+// CHECK-SAME: "title":"baseProperty"
+
+// Checking for baseMethodWithArg
+// CHECK-NEXT: "parentContexts":[{"kind":"objective-c.class","name":"Base","usr":"c:objc(cs)Base"}]
+// CHECK-SAME: "relatedSymbols":[]
+// CHECK-SAME: "relationships":[{"kind":"memberOf","source":"c:objc(cs)Base(im)baseMethodWithArg:","target":"c:objc(cs)Base"
+// CHECK-SAME: "text":"Base method docs"
+// CHECK-SAME: "kind":{"displayName":"Instance Method","identifier":"objective-c.method"}
+// CHECK-SAME: "title":"baseMethodWithArg:"
+
+// Checking for Protocol
+// CHECK-NEXT: "parentContexts":[]
+// CHECK-SAME: "relatedSymbols":[]
+// CHECK-SAME: "relationships":[]
+// CHECK-SAME: "text":"Protocol docs"
+// CHECK-SAME: "kind":{"displayName":"Protocol","identifier":"objective-c.protocol"}
+// CHECK-SAME: "title":"Protocol"
+
+// Checking for protocolProperty
+// CHECK-NEXT: "parentContexts":[{"kind":"objective-c.protocol","name":"Protocol","usr":"c:objc(pl)Protocol"}]
+// CHECK-SAME: "relatedSymbols":[{"accessLevel":"public","declarationLanguage":"objective-c"
+// CHECK-SAME: "isSystem":false
+// CHECK-SAME: "usr":"c:@S at Foo"}]
+// CHECK-SAME: "relationships":[{"kind":"memberOf","source":"c:objc(pl)Protocol(py)protocolProperty","target":"c:objc(pl)Protocol"
+// CHECK-SAME: "text":"Protocol property docs"
+// CHECK-SAME: "kind":{"displayName":"Instance Property","identifier":"objective-c.property"}
+// CHECK-SAME: "title":"protocolProperty"
+
+// Checking for Derived
+// CHECK-NEXT: "parentContexts":[]
+// CHECK-SAME: "relatedSymbols":[{"accessLevel":"public","declarationLanguage":"objective-c"
+// CHECK-SAME: "isSystem":false
+// CHECK-SAME: "usr":"c:objc(cs)Base"}]
+// CHECK-SAME: "relationships":[{"kind":"inheritsFrom","source":"c:objc(cs)Derived","target":"c:objc(cs)Base"
+// CHECK-SAME: "text":"Derived docs"
+// CHECK-SAME: "kind":{"displayName":"Class","identifier":"objective-c.class"}
+// CHECK-SAME: "title":"Derived"
+
+// Checking for derivedMethodWithValue
+// CHECK-NEXT: "parentContexts":[{"kind":"objective-c.class","name":"Derived","usr":"c:objc(cs)Derived"}]
+// CHECK-SAME: "relatedSymbols":[]
+// CHECK-SAME: "relationships":[{"kind":"memberOf","source":"c:objc(cs)Derived(im)derivedMethodWithValue:","target":"c:objc(cs)Derived"
+// CHECK-SAME: "text":"Derived method docs"
+// CHECK-SAME: "kind":{"displayName":"Instance Method","identifier":"objective-c.method"}
+// CHECK-SAME: "title":"derivedMethodWithValue:"
+
+// CHECK-NOT: This won't show up in docs because we can't serialize it
+// CHECK-NOT: Derived method in category docs, won't show up either.

diff  --git a/clang/tools/c-index-test/c-index-test.c b/clang/tools/c-index-test/c-index-test.c
index f116111ffacec..448435e83027c 100644
--- a/clang/tools/c-index-test/c-index-test.c
+++ b/clang/tools/c-index-test/c-index-test.c
@@ -3,7 +3,6 @@
 #include "clang-c/BuildSystem.h"
 #include "clang-c/CXCompilationDatabase.h"
 #include "clang-c/CXErrorCode.h"
-#include "clang-c/CXSourceLocation.h"
 #include "clang-c/CXString.h"
 #include "clang-c/Documentation.h"
 #include "clang-c/Index.h"
@@ -4882,21 +4881,6 @@ static int perform_test_single_symbol_sgf(const char *input, int argc,
   return result;
 }
 
-static void inspect_single_symbol_sgf_cursor(CXCursor Cursor) {
-  CXSourceLocation CursorLoc;
-  CXString SGFData;
-  const char *SGF;
-  unsigned line, column;
-  CursorLoc = clang_getCursorLocation(Cursor);
-  clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
-  printf("%d:%d: ", line, column);
-
-  SGFData = clang_getSymbolGraphForCursor(Cursor);
-  SGF = clang_getCString(SGFData);
-  if (SGF)
-    printf("%s\n", SGF);
-}
-
 /******************************************************************************/
 /* Command line processing.                                                   */
 /******************************************************************************/
@@ -4956,7 +4940,6 @@ static void print_usage(void) {
     "       c-index-test -print-usr-file <file>\n");
   fprintf(stderr,
           "       c-index-test -single-symbol-sgfs <symbol filter> {<args>*}\n"
-          "       c-index-test -single-symbol-sgf-at=<site> {<args>*}\n"
           "       c-index-test -single-symbol-sgf-for=<usr> {<args>}*\n");
   fprintf(stderr,
     "       c-index-test -write-pch <file> <compiler arguments>\n"
@@ -5093,9 +5076,6 @@ int cindextest_main(int argc, const char **argv) {
   else if (argc > 3 && strcmp(argv[1], "-single-symbol-sgfs") == 0)
     return perform_test_load_source(argc - 3, argv + 3, argv[2],
                                     PrintSingleSymbolSGFs, NULL);
-  else if (argc > 2 && strstr(argv[1], "-single-symbol-sgf-at=") == argv[1])
-    return inspect_cursor_at(
-        argc, argv, "-single-symbol-sgf-at=", inspect_single_symbol_sgf_cursor);
   else if (argc > 2 && strstr(argv[1], "-single-symbol-sgf-for=") == argv[1])
     return perform_test_single_symbol_sgf(argv[1], argc - 2, argv + 2);
 

diff  --git a/clang/tools/libclang/CXExtractAPI.cpp b/clang/tools/libclang/CXExtractAPI.cpp
index 9128e891538a8..787334ab1bbb2 100644
--- a/clang/tools/libclang/CXExtractAPI.cpp
+++ b/clang/tools/libclang/CXExtractAPI.cpp
@@ -18,7 +18,6 @@
 #include "clang-c/Index.h"
 #include "clang-c/Platform.h"
 #include "clang/AST/Decl.h"
-#include "clang/AST/DeclObjC.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/ExtractAPI/API.h"
 #include "clang/ExtractAPI/ExtractAPIVisitor.h"
@@ -35,73 +34,13 @@
 using namespace clang;
 using namespace clang::extractapi;
 
-namespace {
-struct LibClangExtractAPIVisitor
-    : ExtractAPIVisitor<LibClangExtractAPIVisitor> {
-  using Base = ExtractAPIVisitor<LibClangExtractAPIVisitor>;
-
-  LibClangExtractAPIVisitor(ASTContext &Context, APISet &API)
-      : ExtractAPIVisitor<LibClangExtractAPIVisitor>(Context, API) {}
-
-  const RawComment *fetchRawCommentForDecl(const Decl *D) const {
-    return Context.getRawCommentForAnyRedecl(D);
-  }
-
-  // We need to visit implementations as well to ensure that when a user clicks
-  // on a method defined only within the implementation that we can still
-  // provide a symbol graph for it.
-  bool VisitObjCImplementationDecl(const ObjCImplementationDecl *Decl) {
-    if (!shouldDeclBeIncluded(Decl))
-      return true;
-
-    const ObjCInterfaceDecl *Interface = Decl->getClassInterface();
-    StringRef Name = Interface->getName();
-    StringRef USR = API.recordUSR(Decl);
-    PresumedLoc Loc =
-        Context.getSourceManager().getPresumedLoc(Decl->getLocation());
-    LinkageInfo Linkage = Decl->getLinkageAndVisibility();
-    DocComment Comment;
-    if (auto *RawComment = fetchRawCommentForDecl(Interface))
-      Comment = RawComment->getFormattedLines(Context.getSourceManager(),
-                                              Context.getDiagnostics());
-
-    // Build declaration fragments and sub-heading by generating them for the
-    // interface.
-    DeclarationFragments Declaration =
-        DeclarationFragmentsBuilder::getFragmentsForObjCInterface(Interface);
-    DeclarationFragments SubHeading =
-        DeclarationFragmentsBuilder::getSubHeading(Decl);
-
-    // Collect super class information.
-    SymbolReference SuperClass;
-    if (const auto *SuperClassDecl = Decl->getSuperClass()) {
-      SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString();
-      SuperClass.USR = API.recordUSR(SuperClassDecl);
-    }
-
-    ObjCInterfaceRecord *ObjCInterfaceRecord = API.addObjCInterface(
-        Name, USR, Loc, AvailabilitySet(Decl), Linkage, Comment, Declaration,
-        SubHeading, SuperClass, isInSystemHeader(Decl));
-
-    // Record all methods (selectors). This doesn't include automatically
-    // synthesized property methods.
-    recordObjCMethods(ObjCInterfaceRecord, Decl->methods());
-    recordObjCProperties(ObjCInterfaceRecord, Decl->properties());
-    recordObjCInstanceVariables(ObjCInterfaceRecord, Decl->ivars());
-
-    return true;
-  }
-};
-} // namespace
-
 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(APISet, CXAPISet)
 
-static void WalkupFromMostDerivedType(LibClangExtractAPIVisitor &Visitor,
-                                      Decl *D);
+static void WalkupFromMostDerivedType(ExtractAPIVisitor &Visitor, Decl *D);
 
 template <typename DeclTy>
 static bool WalkupParentContext(DeclContext *Parent,
-                                LibClangExtractAPIVisitor &Visitor) {
+                                ExtractAPIVisitor &Visitor) {
   if (auto *D = dyn_cast<DeclTy>(Parent)) {
     WalkupFromMostDerivedType(Visitor, D);
     return true;
@@ -109,8 +48,7 @@ static bool WalkupParentContext(DeclContext *Parent,
   return false;
 }
 
-static void WalkupFromMostDerivedType(LibClangExtractAPIVisitor &Visitor,
-                                      Decl *D) {
+static void WalkupFromMostDerivedType(ExtractAPIVisitor &Visitor, Decl *D) {
   switch (D->getKind()) {
 #define ABSTRACT_DECL(DECL)
 #define DECL(CLASS, BASE)                                                      \
@@ -146,7 +84,8 @@ enum CXErrorCode clang_createAPISet(CXTranslationUnit tu, CXAPISet *out_api) {
   auto Lang = Unit->getInputKind().getLanguage();
   APISet *API = new APISet(Ctx.getTargetInfo().getTriple(), Lang,
                            Unit->getMainFileName().str());
-  LibClangExtractAPIVisitor Visitor(Ctx, *API);
+  ExtractAPIVisitor Visitor(
+      Ctx, [](SourceLocation Loc) { return true; }, *API);
 
   for (auto It = Unit->top_level_begin(); It != Unit->top_level_end(); ++It) {
     Visitor.TraverseDecl(*It);
@@ -168,50 +107,45 @@ CXString clang_getSymbolGraphForUSR(const char *usr, CXAPISet api) {
 }
 
 CXString clang_getSymbolGraphForCursor(CXCursor cursor) {
-  cursor = clang_getCursorReferenced(cursor);
   CXCursorKind Kind = clang_getCursorKind(cursor);
-  if (!clang_isDeclaration(Kind))
-    return cxstring::createNull();
+  if (clang_isDeclaration(Kind)) {
+    const Decl *D = cxcursor::getCursorDecl(cursor);
 
-  const Decl *D = cxcursor::getCursorDecl(cursor);
+    if (!D)
+      return cxstring::createNull();
 
-  if (!D)
-    return cxstring::createNull();
+    CXTranslationUnit TU = cxcursor::getCursorTU(cursor);
+    if (!TU)
+      return cxstring::createNull();
 
-  CXTranslationUnit TU = cxcursor::getCursorTU(cursor);
-  if (!TU)
-    return cxstring::createNull();
+    ASTUnit *Unit = cxtu::getASTUnit(TU);
 
-  ASTUnit *Unit = cxtu::getASTUnit(TU);
+    auto &Ctx = Unit->getASTContext();
+    auto Lang = Unit->getInputKind().getLanguage();
+    APISet API(Ctx.getTargetInfo().getTriple(), Lang,
+               Unit->getMainFileName().str());
+    ExtractAPIVisitor Visitor(
+        Ctx, [](SourceLocation Loc) { return true; }, API);
 
-  auto &Ctx = Unit->getASTContext();
-
-  auto Lang = Unit->getInputKind().getLanguage();
-  APISet API(Ctx.getTargetInfo().getTriple(), Lang,
-             Unit->getMainFileName().str());
-  LibClangExtractAPIVisitor Visitor(Ctx, API);
+    SmallString<128> USR;
+    if (index::generateUSRForDecl(D, USR))
+      return cxstring::createNull();
 
-  const Decl *CanonicalDecl = D->getCanonicalDecl();
-  CanonicalDecl = CanonicalDecl ? CanonicalDecl : D;
+    WalkupFromMostDerivedType(Visitor, const_cast<Decl *>(D));
+    auto *Record = API.findRecordForUSR(USR);
 
-  SmallString<128> USR;
-  if (index::generateUSRForDecl(CanonicalDecl, USR))
-    return cxstring::createNull();
+    if (!Record)
+      return cxstring::createNull();
 
-  WalkupFromMostDerivedType(Visitor, const_cast<Decl *>(CanonicalDecl));
-  auto *Record = API.findRecordForUSR(USR);
-
-  if (!Record)
-    return cxstring::createNull();
+    for (const auto &Fragment : Record->Declaration.getFragments()) {
+      if (Fragment.Declaration)
+        WalkupFromMostDerivedType(Visitor,
+                                  const_cast<Decl *>(Fragment.Declaration));
+    }
 
-  for (const auto &Fragment : Record->Declaration.getFragments()) {
-    if (Fragment.Declaration)
-      WalkupFromMostDerivedType(Visitor,
-                                const_cast<Decl *>(Fragment.Declaration));
+    if (auto SGF = SymbolGraphSerializer::serializeSingleSymbolSGF(USR, API))
+      return GenerateCXStringFromSymbolGraphData(std::move(*SGF));
   }
 
-  if (auto SGF = SymbolGraphSerializer::serializeSingleSymbolSGF(USR, API))
-    return GenerateCXStringFromSymbolGraphData(std::move(*SGF));
-
   return cxstring::createNull();
 }


        


More information about the cfe-commits mailing list