[clang] 142c3d9 - [clang][ExtractAPI] Reland ExtractAPI for libclang improvements
Daniel Grumberg via cfe-commits
cfe-commits at lists.llvm.org
Thu Mar 30 10:14:18 PDT 2023
Author: Daniel Grumberg
Date: 2023-03-30T18:13:58+01:00
New Revision: 142c3d9d1414847fd154c300ff12505283027505
URL: https://github.com/llvm/llvm-project/commit/142c3d9d1414847fd154c300ff12505283027505
DIFF: https://github.com/llvm/llvm-project/commit/142c3d9d1414847fd154c300ff12505283027505.diff
LOG: [clang][ExtractAPI] Reland ExtractAPI for libclang improvements
This relands the changes that were originally introduced by:
- https://reviews.llvm.org/D146656
- https://reviews.llvm.org/D147138
This also fixes the leak that led to these changes being reverted
Differential Revision: https://reviews.llvm.org/D147234
Added:
clang/include/clang/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/Serialization/SymbolGraphSerializer.cpp
clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp
clang/test/Index/extract-api-cursor.m
clang/test/Index/extract-api-usr.m
clang/tools/c-index-test/c-index-test.c
clang/tools/libclang/CXExtractAPI.cpp
Removed:
clang/lib/ExtractAPI/ExtractAPIVisitor.cpp
clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.h
################################################################################
diff --git a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
index f6546fb4776a6..a31648b80195a 100644
--- a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
+++ b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h
@@ -14,24 +14,27 @@
#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 "llvm/ADT/FunctionExtras.h"
+#include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h"
+#include <type_traits>
namespace clang {
namespace extractapi {
+namespace impl {
-/// 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)) {}
+template <typename Derived>
+class ExtractAPIVisitorBase : public RecursiveASTVisitor<Derived> {
+protected:
+ ExtractAPIVisitorBase(ASTContext &Context, APISet &API)
+ : Context(Context), API(API) {}
+public:
const APISet &getAPI() const { return API; }
bool VisitVarDecl(const VarDecl *Decl);
@@ -50,7 +53,11 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
bool VisitObjCCategoryDecl(const ObjCCategoryDecl *Decl);
-private:
+ bool shouldDeclBeIncluded(const Decl *Decl) const;
+
+ const RawComment *fetchRawCommentForDecl(const Decl *Decl) const;
+
+protected:
/// Collect API information for the enum constants and associate with the
/// parent enum.
void recordEnumConstants(EnumRecord *EnumRecord,
@@ -77,9 +84,582 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
void recordObjCProtocols(ObjCContainerRecord *Container,
ObjCInterfaceDecl::protocol_range Protocols);
+
ASTContext &Context;
APISet &API;
- llvm::unique_function<bool(SourceLocation)> LocationChecker;
+
+ 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);
+ }
};
} // namespace extractapi
diff --git a/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.h b/clang/include/clang/ExtractAPI/TypedefUnderlyingTypeResolver.h
similarity index 100%
rename from clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.h
rename to clang/include/clang/ExtractAPI/TypedefUnderlyingTypeResolver.h
diff --git a/clang/lib/ExtractAPI/CMakeLists.txt b/clang/lib/ExtractAPI/CMakeLists.txt
index 80fafcd6a0196..153d4b992fda7 100644
--- a/clang/lib/ExtractAPI/CMakeLists.txt
+++ b/clang/lib/ExtractAPI/CMakeLists.txt
@@ -8,7 +8,6 @@ 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 c42a1de2fd358..675d4e8dc8638 100644
--- a/clang/lib/ExtractAPI/DeclarationFragments.cpp
+++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp
@@ -12,7 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/ExtractAPI/DeclarationFragments.h"
-#include "TypedefUnderlyingTypeResolver.h"
+#include "clang/ExtractAPI/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 c1e47b10a39fe..c27b2d025374a 100644
--- a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
+++ b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
@@ -12,8 +12,10 @@
///
//===----------------------------------------------------------------------===//
+#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"
@@ -33,6 +35,7 @@
#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"
@@ -219,11 +222,34 @@ 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(Context, *LCF, API), LCF(std::move(LCF)) {}
+ : Visitor(*LCF, Context, API), LCF(std::move(LCF)) {}
void HandleTranslationUnit(ASTContext &Context) override {
// Use ExtractAPIVisitor to traverse symbol declarations in the context.
@@ -231,7 +257,7 @@ class ExtractAPIConsumer : public ASTConsumer {
}
private:
- ExtractAPIVisitor Visitor;
+ BatchExtractAPIVisitor Visitor;
std::unique_ptr<LocationFileChecker> LCF;
};
diff --git a/clang/lib/ExtractAPI/ExtractAPIVisitor.cpp b/clang/lib/ExtractAPI/ExtractAPIVisitor.cpp
deleted file mode 100644
index 24260cf89383d..0000000000000
--- a/clang/lib/ExtractAPI/ExtractAPIVisitor.cpp
+++ /dev/null
@@ -1,560 +0,0 @@
-//===- 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/Serialization/SymbolGraphSerializer.cpp b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
index 8a98f5cf0c71f..7676c74af6869 100644
--- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
+++ b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
@@ -547,10 +547,6 @@ Array generateParentContexts(const RecordTy &Record, const APISet &API,
serializeParentContext(PC, Lang));
});
- // The last component would be the record itself so let's remove it.
- if (!ParentContexts.empty())
- ParentContexts.pop_back();
-
return ParentContexts;
}
diff --git a/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp b/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp
index 3da2424ea7263..3a5f62c9b2e6c 100644
--- a/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp
+++ b/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp
@@ -11,7 +11,7 @@
///
//===----------------------------------------------------------------------===//
-#include "TypedefUnderlyingTypeResolver.h"
+#include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h"
#include "clang/Index/USRGeneration.h"
using namespace clang;
diff --git a/clang/test/Index/extract-api-cursor.m b/clang/test/Index/extract-api-cursor.m
index 078f2f52e215c..1b27b6f61437b 100644
--- a/clang/test/Index/extract-api-cursor.m
+++ b/clang/test/Index/extract-api-cursor.m
@@ -1,3 +1,5 @@
+// Test is line- and column-sensitive. Run lines are below
+
/// Foo docs
struct Foo {
/// Bar docs
@@ -25,91 +27,94 @@ @interface Derived: Base
- (void)derivedMethodWithValue:(id<Protocol>)value;
@end
-/// 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;
+ at implementation Derived
+- (void)derivedMethodWithValue:(id<Protocol>)value {
+ int a = 5;
+}
@end
-// 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.
+// RUN: c-index-test -single-symbol-sgf-at=%s:4:9 local %s | FileCheck -check-prefix=CHECK-FOO %s
+// CHECK-FOO: "parentContexts":[{"kind":"objective-c.struct","name":"Foo","usr":"c:@S at Foo"}]
+// 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"},{"kind":"objective-c.property","name":"bar","usr":"c:@S at Foo@FI at bar"}]
+// 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":[{"kind":"objective-c.class","name":"Base","usr":"c:objc(cs)Base"}]
+// 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"},{"kind":"objective-c.property","name":"baseProperty","usr":"c:objc(cs)Base(py)baseProperty"}]
+// 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"},{"kind":"objective-c.method","name":"baseMethodWithArg:","usr":"c:objc(cs)Base(im)baseMethodWithArg:"}]
+// 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":[{"kind":"objective-c.protocol","name":"Protocol","usr":"c:objc(pl)Protocol"}]
+// 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"},{"kind":"objective-c.property","name":"protocolProperty","usr":"c:objc(pl)Protocol(py)protocolProperty"}]
+// 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":[{"kind":"objective-c.class","name":"Derived","usr":"c:objc(cs)Derived"}]
+// 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"},{"kind":"objective-c.method","name":"derivedMethodWithValue:","usr":"c:objc(cs)Derived(im)derivedMethodWithValue:"}]
+// 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"},{"kind":"objective-c.method","name":"derivedMethodWithValue:","usr":"c:objc(cs)Derived(im)derivedMethodWithValue:"}]
+// 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:"
diff --git a/clang/test/Index/extract-api-usr.m b/clang/test/Index/extract-api-usr.m
index 12bfb0a676e66..0b468ee916708 100644
--- a/clang/test/Index/extract-api-usr.m
+++ b/clang/test/Index/extract-api-usr.m
@@ -28,7 +28,7 @@ - (void)derivedMethodWithValue:(id<Protocol>)value;
// Checking for Foo
// RUN: c-index-test "-single-symbol-sgf-for=c:@S at Foo" %s | FileCheck -check-prefix=CHECK-FOO %s
-// CHECK-FOO: "parentContexts":[]
+// CHECK-FOO: "parentContexts":[{"kind":"objective-c.struct","name":"Foo","usr":"c:@S at Foo"}]
// CHECK-FOO-SAME: "relatedSymbols":[]
// CHECK-FOO-SAME: "relationships":[]
// CHECK-FOO-SAME: "text":"Foo docs"
@@ -38,7 +38,7 @@ - (void)derivedMethodWithValue:(id<Protocol>)value;
// Checking for bar
// RUN: c-index-test "-single-symbol-sgf-for=c:@S at Foo@FI at bar" %s | FileCheck -check-prefix=CHECK-BAR %s
-// CHECK-BAR: "parentContexts":[{"kind":"objective-c.struct","name":"Foo","usr":"c:@S at Foo"}]
+// CHECK-BAR: "parentContexts":[{"kind":"objective-c.struct","name":"Foo","usr":"c:@S at Foo"},{"kind":"objective-c.property","name":"bar","usr":"c:@S at Foo@FI at bar"}]
// CHECK-BAR-SAME: "relatedSymbols":[]
// CHECK-BAR-SAME: "relationships":[{"kind":"memberOf","source":"c:@S at Foo@FI at bar","target":"c:@S at Foo"
// CHECK-BAR-SAME: "text":"Bar docs"
@@ -47,7 +47,7 @@ - (void)derivedMethodWithValue:(id<Protocol>)value;
// Checking for Base
// RUN: c-index-test "-single-symbol-sgf-for=c:objc(cs)Base" %s | FileCheck -check-prefix=CHECK-BASE %s
-// CHECK-BASE: "parentContexts":[]
+// CHECK-BASE: "parentContexts":[{"kind":"objective-c.class","name":"Base","usr":"c:objc(cs)Base"}]
// CHECK-BASE-SAME: "relatedSymbols":[]
// CHECK-BASE-SAME: "relationships":[]
// CHECK-BASE-SAME: "text":"Base docs"
@@ -56,7 +56,7 @@ - (void)derivedMethodWithValue:(id<Protocol>)value;
// Checking for baseProperty
// RUN: c-index-test "-single-symbol-sgf-for=c:objc(cs)Base(py)baseProperty" %s | FileCheck -check-prefix=CHECK-BASEPROP %s
-// CHECK-BASEPROP: "parentContexts":[{"kind":"objective-c.class","name":"Base","usr":"c:objc(cs)Base"}]
+// CHECK-BASEPROP: "parentContexts":[{"kind":"objective-c.class","name":"Base","usr":"c:objc(cs)Base"},{"kind":"objective-c.property","name":"baseProperty","usr":"c:objc(cs)Base(py)baseProperty"}]
// CHECK-BASEPROP-SAME:"relatedSymbols":[{"accessLevel":"public","declarationLanguage":"objective-c"
// CHECK-BASEPROP-SAME: "isSystem":false
// CHECK-BASEPROP-SAME: "usr":"c:@S at Foo"}]
@@ -67,7 +67,7 @@ - (void)derivedMethodWithValue:(id<Protocol>)value;
// Checking for baseMethodWithArg
// RUN: c-index-test "-single-symbol-sgf-for=c:objc(cs)Base(im)baseMethodWithArg:" %s | FileCheck -check-prefix=CHECK-BASEMETHOD %s
-// CHECK-BASEMETHOD: "parentContexts":[{"kind":"objective-c.class","name":"Base","usr":"c:objc(cs)Base"}]
+// CHECK-BASEMETHOD: "parentContexts":[{"kind":"objective-c.class","name":"Base","usr":"c:objc(cs)Base"},{"kind":"objective-c.method","name":"baseMethodWithArg:","usr":"c:objc(cs)Base(im)baseMethodWithArg:"}]
// CHECK-BASEMETHOD-SAME:"relatedSymbols":[]
// CHECK-BASEMETHOD-SAME: "relationships":[{"kind":"memberOf","source":"c:objc(cs)Base(im)baseMethodWithArg:","target":"c:objc(cs)Base"
// CHECK-BASEMETHOD-SAME: "text":"Base method docs"
@@ -76,7 +76,7 @@ - (void)derivedMethodWithValue:(id<Protocol>)value;
// Checking for Protocol
// RUN: c-index-test "-single-symbol-sgf-for=c:objc(pl)Protocol" %s | FileCheck -check-prefix=CHECK-PROT %s
-// CHECK-PROT: "parentContexts":[]
+// CHECK-PROT: "parentContexts":[{"kind":"objective-c.protocol","name":"Protocol","usr":"c:objc(pl)Protocol"}]
// CHECK-PROT-SAME: "relatedSymbols":[]
// CHECK-PROT-SAME: "relationships":[]
// CHECK-PROT-SAME: "text":"Protocol docs"
@@ -85,7 +85,7 @@ - (void)derivedMethodWithValue:(id<Protocol>)value;
// Checking for protocolProperty
// RUN: c-index-test "-single-symbol-sgf-for=c:objc(pl)Protocol(py)protocolProperty" %s | FileCheck -check-prefix=CHECK-PROTPROP %s
-// CHECK-PROTPROP: "parentContexts":[{"kind":"objective-c.protocol","name":"Protocol","usr":"c:objc(pl)Protocol"}]
+// CHECK-PROTPROP: "parentContexts":[{"kind":"objective-c.protocol","name":"Protocol","usr":"c:objc(pl)Protocol"},{"kind":"objective-c.property","name":"protocolProperty","usr":"c:objc(pl)Protocol(py)protocolProperty"}]
// CHECK-PROTPROP-SAME:"relatedSymbols":[{"accessLevel":"public","declarationLanguage":"objective-c"
// CHECK-PROTPROP-SAME: "isSystem":false
// CHECK-PROTPROP-SAME: "usr":"c:@S at Foo"}]
@@ -96,7 +96,7 @@ - (void)derivedMethodWithValue:(id<Protocol>)value;
// Checking for Derived
// RUN: c-index-test "-single-symbol-sgf-for=c:objc(cs)Derived" %s | FileCheck -check-prefix=CHECK-DERIVED %s
-// CHECK-DERIVED: "parentContexts":[]
+// CHECK-DERIVED: "parentContexts":[{"kind":"objective-c.class","name":"Derived","usr":"c:objc(cs)Derived"}]
// CHECK-DERIVED-SAME:"relatedSymbols":[{"accessLevel":"public","declarationLanguage":"objective-c"
// CHECK-DERIVED-SAME: "isSystem":false
// CHECK-DERIVED-SAME: "usr":"c:objc(cs)Base"}]
@@ -107,7 +107,7 @@ - (void)derivedMethodWithValue:(id<Protocol>)value;
// Checking for derivedMethodWithValue
// RUN: c-index-test "-single-symbol-sgf-for=c:objc(cs)Derived(im)derivedMethodWithValue:" %s | FileCheck -check-prefix=CHECK-DERIVEDMETHOD %s
-// CHECK-DERIVEDMETHOD: "parentContexts":[{"kind":"objective-c.class","name":"Derived","usr":"c:objc(cs)Derived"}]
+// CHECK-DERIVEDMETHOD: "parentContexts":[{"kind":"objective-c.class","name":"Derived","usr":"c:objc(cs)Derived"},{"kind":"objective-c.method","name":"derivedMethodWithValue:","usr":"c:objc(cs)Derived(im)derivedMethodWithValue:"}]
// CHECK-DERIVEDMETHOD-SAME:"relatedSymbols":[]
// CHECK-DERIVEDMETHOD-SAME: "relationships":[{"kind":"memberOf","source":"c:objc(cs)Derived(im)derivedMethodWithValue:","target":"c:objc(cs)Derived"
// CHECK-DERIVEDMETHOD-SAME: "text":"Derived method docs"
diff --git a/clang/tools/c-index-test/c-index-test.c b/clang/tools/c-index-test/c-index-test.c
index 448435e83027c..68a560ca15cf4 100644
--- a/clang/tools/c-index-test/c-index-test.c
+++ b/clang/tools/c-index-test/c-index-test.c
@@ -3,6 +3,7 @@
#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"
@@ -4881,6 +4882,22 @@ 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);
+
+ SGFData = clang_getSymbolGraphForCursor(Cursor);
+ SGF = clang_getCString(SGFData);
+ if (SGF)
+ printf("%d:%d: %s\n", line, column, SGF);
+
+ clang_disposeString(SGFData);
+}
+
/******************************************************************************/
/* Command line processing. */
/******************************************************************************/
@@ -4940,6 +4957,7 @@ 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"
@@ -5076,6 +5094,9 @@ 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 787334ab1bbb2..9128e891538a8 100644
--- a/clang/tools/libclang/CXExtractAPI.cpp
+++ b/clang/tools/libclang/CXExtractAPI.cpp
@@ -18,6 +18,7 @@
#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"
@@ -34,13 +35,73 @@
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(ExtractAPIVisitor &Visitor, Decl *D);
+static void WalkupFromMostDerivedType(LibClangExtractAPIVisitor &Visitor,
+ Decl *D);
template <typename DeclTy>
static bool WalkupParentContext(DeclContext *Parent,
- ExtractAPIVisitor &Visitor) {
+ LibClangExtractAPIVisitor &Visitor) {
if (auto *D = dyn_cast<DeclTy>(Parent)) {
WalkupFromMostDerivedType(Visitor, D);
return true;
@@ -48,7 +109,8 @@ static bool WalkupParentContext(DeclContext *Parent,
return false;
}
-static void WalkupFromMostDerivedType(ExtractAPIVisitor &Visitor, Decl *D) {
+static void WalkupFromMostDerivedType(LibClangExtractAPIVisitor &Visitor,
+ Decl *D) {
switch (D->getKind()) {
#define ABSTRACT_DECL(DECL)
#define DECL(CLASS, BASE) \
@@ -84,8 +146,7 @@ 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());
- ExtractAPIVisitor Visitor(
- Ctx, [](SourceLocation Loc) { return true; }, *API);
+ LibClangExtractAPIVisitor Visitor(Ctx, *API);
for (auto It = Unit->top_level_begin(); It != Unit->top_level_end(); ++It) {
Visitor.TraverseDecl(*It);
@@ -107,45 +168,50 @@ 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)) {
- const Decl *D = cxcursor::getCursorDecl(cursor);
+ if (!clang_isDeclaration(Kind))
+ return cxstring::createNull();
- if (!D)
- return cxstring::createNull();
+ const Decl *D = cxcursor::getCursorDecl(cursor);
- CXTranslationUnit TU = cxcursor::getCursorTU(cursor);
- if (!TU)
- return cxstring::createNull();
+ if (!D)
+ return cxstring::createNull();
- ASTUnit *Unit = cxtu::getASTUnit(TU);
+ CXTranslationUnit TU = cxcursor::getCursorTU(cursor);
+ if (!TU)
+ return cxstring::createNull();
- 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);
+ ASTUnit *Unit = cxtu::getASTUnit(TU);
- SmallString<128> USR;
- if (index::generateUSRForDecl(D, USR))
- return cxstring::createNull();
+ auto &Ctx = Unit->getASTContext();
- WalkupFromMostDerivedType(Visitor, const_cast<Decl *>(D));
- auto *Record = API.findRecordForUSR(USR);
+ auto Lang = Unit->getInputKind().getLanguage();
+ APISet API(Ctx.getTargetInfo().getTriple(), Lang,
+ Unit->getMainFileName().str());
+ LibClangExtractAPIVisitor Visitor(Ctx, API);
- if (!Record)
- return cxstring::createNull();
+ const Decl *CanonicalDecl = D->getCanonicalDecl();
+ CanonicalDecl = CanonicalDecl ? CanonicalDecl : D;
- for (const auto &Fragment : Record->Declaration.getFragments()) {
- if (Fragment.Declaration)
- WalkupFromMostDerivedType(Visitor,
- const_cast<Decl *>(Fragment.Declaration));
- }
+ SmallString<128> USR;
+ if (index::generateUSRForDecl(CanonicalDecl, USR))
+ return cxstring::createNull();
- if (auto SGF = SymbolGraphSerializer::serializeSingleSymbolSGF(USR, API))
- return GenerateCXStringFromSymbolGraphData(std::move(*SGF));
+ 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));
}
+ if (auto SGF = SymbolGraphSerializer::serializeSingleSymbolSGF(USR, API))
+ return GenerateCXStringFromSymbolGraphData(std::move(*SGF));
+
return cxstring::createNull();
}
More information about the cfe-commits
mailing list