diff --git a/clang/include/clang/AST/ASTFwd.h b/clang/include/clang/AST/ASTFwd.h --- a/clang/include/clang/AST/ASTFwd.h +++ b/clang/include/clang/AST/ASTFwd.h @@ -33,6 +33,7 @@ class Attr; #define ATTR(A) class A##Attr; #include "clang/Basic/AttrList.inc" +class ObjCProtocolLoc; } // end namespace clang diff --git a/clang/include/clang/AST/ASTTypeTraits.h b/clang/include/clang/AST/ASTTypeTraits.h --- a/clang/include/clang/AST/ASTTypeTraits.h +++ b/clang/include/clang/AST/ASTTypeTraits.h @@ -160,6 +160,7 @@ NKI_Attr, #define ATTR(A) NKI_##A##Attr, #include "clang/Basic/AttrList.inc" + NKI_ObjCProtocolLoc, NKI_NumberOfKinds }; @@ -213,6 +214,7 @@ KIND_TO_KIND_ID(Type) KIND_TO_KIND_ID(OMPClause) KIND_TO_KIND_ID(Attr) +KIND_TO_KIND_ID(ObjCProtocolLoc) KIND_TO_KIND_ID(CXXBaseSpecifier) #define DECL(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Decl) #include "clang/AST/DeclNodes.inc" @@ -499,7 +501,7 @@ /// have storage or unique pointers and thus need to be stored by value. llvm::AlignedCharArrayUnion + QualType, TypeLoc, ObjCProtocolLoc> Storage; }; @@ -570,6 +572,10 @@ struct DynTypedNode::BaseConverter : public PtrConverter {}; +template <> +struct DynTypedNode::BaseConverter + : public ValueConverter {}; + // The only operation we allow on unsupported types is \c get. // This allows to conveniently use \c DynTypedNode when having an arbitrary // AST node that is not supported, but prevents misuse - a user cannot create diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -324,6 +324,12 @@ /// \returns false if the visitation was terminated early, true otherwise. bool TraverseConceptReference(const ConceptReference &C); + /// Recursively visit an Objective-C protocol reference with location + /// information. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseObjCProtocolLoc(ObjCProtocolLoc ProtocolLoc); + // ---- Methods on Attrs ---- // Visit an attribute. @@ -1340,7 +1346,14 @@ DEF_TRAVERSE_TYPELOC(PackExpansionType, { TRY_TO(TraverseTypeLoc(TL.getPatternLoc())); }) -DEF_TRAVERSE_TYPELOC(ObjCTypeParamType, {}) +DEF_TRAVERSE_TYPELOC(ObjCTypeParamType, { + for (unsigned i = 0, n = TL.getNumProtocols(); i != n; ++i) { + ObjCProtocolLoc ProtocolLoc; + ProtocolLoc.Protocol = TL.getProtocol(i); + ProtocolLoc.Loc = TL.getProtocolLoc(i); + TRY_TO(TraverseObjCProtocolLoc(ProtocolLoc)); + } +}) DEF_TRAVERSE_TYPELOC(ObjCInterfaceType, {}) @@ -1351,6 +1364,12 @@ TRY_TO(TraverseTypeLoc(TL.getBaseLoc())); for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) TRY_TO(TraverseTypeLoc(TL.getTypeArgTInfo(i)->getTypeLoc())); + for (unsigned i = 0, n = TL.getNumProtocols(); i != n; ++i) { + ObjCProtocolLoc ProtocolLoc; + ProtocolLoc.Protocol = TL.getProtocol(i); + ProtocolLoc.Loc = TL.getProtocolLoc(i); + TRY_TO(TraverseObjCProtocolLoc(ProtocolLoc)); + } }) DEF_TRAVERSE_TYPELOC(ObjCObjectPointerType, @@ -1541,12 +1560,18 @@ DEF_TRAVERSE_DECL(ObjCCompatibleAliasDecl, {// FIXME: implement }) -DEF_TRAVERSE_DECL(ObjCCategoryDecl, {// FIXME: implement +DEF_TRAVERSE_DECL(ObjCCategoryDecl, { if (ObjCTypeParamList *typeParamList = D->getTypeParamList()) { for (auto typeParam : *typeParamList) { TRY_TO(TraverseObjCTypeParamDecl(typeParam)); } } + for (auto It : llvm::zip(D->protocols(), D->protocol_locs())) { + ObjCProtocolLoc ProtocolLoc; + ProtocolLoc.Protocol = std::get<0>(It); + ProtocolLoc.Loc = std::get<1>(It); + TRY_TO(TraverseObjCProtocolLoc(ProtocolLoc)); + } }) DEF_TRAVERSE_DECL(ObjCCategoryImplDecl, {// FIXME: implement @@ -1555,7 +1580,7 @@ DEF_TRAVERSE_DECL(ObjCImplementationDecl, {// FIXME: implement }) -DEF_TRAVERSE_DECL(ObjCInterfaceDecl, {// FIXME: implement +DEF_TRAVERSE_DECL(ObjCInterfaceDecl, { if (ObjCTypeParamList *typeParamList = D->getTypeParamListAsWritten()) { for (auto typeParam : *typeParamList) { TRY_TO(TraverseObjCTypeParamDecl(typeParam)); @@ -1565,10 +1590,26 @@ if (TypeSourceInfo *superTInfo = D->getSuperClassTInfo()) { TRY_TO(TraverseTypeLoc(superTInfo->getTypeLoc())); } + if (D->isThisDeclarationADefinition()) { + for (auto It : llvm::zip(D->protocols(), D->protocol_locs())) { + ObjCProtocolLoc ProtocolLoc; + ProtocolLoc.Protocol = std::get<0>(It); + ProtocolLoc.Loc = std::get<1>(It); + TRY_TO(TraverseObjCProtocolLoc(ProtocolLoc)); + } + } }) -DEF_TRAVERSE_DECL(ObjCProtocolDecl, {// FIXME: implement - }) +DEF_TRAVERSE_DECL(ObjCProtocolDecl, { + if (D->isThisDeclarationADefinition()) { + for (auto It : llvm::zip(D->protocols(), D->protocol_locs())) { + ObjCProtocolLoc ProtocolLoc; + ProtocolLoc.Protocol = std::get<0>(It); + ProtocolLoc.Loc = std::get<1>(It); + TRY_TO(TraverseObjCProtocolLoc(ProtocolLoc)); + } + } +}) DEF_TRAVERSE_DECL(ObjCMethodDecl, { if (D->getReturnTypeSourceInfo()) { @@ -2409,6 +2450,12 @@ return true; } +template +bool RecursiveASTVisitor::TraverseObjCProtocolLoc( + ObjCProtocolLoc ProtocolLoc) { + return true; +} + // If shouldVisitImplicitCode() returns false, this method traverses only the // syntactic form of InitListExpr. // If shouldVisitImplicitCode() return true, this method is called once for diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -2607,6 +2607,20 @@ : public InheritingConcreteTypeLoc {}; +class ObjCProtocolLoc { +public: + const ObjCProtocolDecl *Protocol = nullptr; + SourceLocation Loc = SourceLocation(); + + /// Get the full source range. + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(Loc, Loc); + } + + /// Evaluates true when this protocol loc is valid/non-empty. + explicit operator bool() const { return Protocol; } +}; + } // namespace clang #endif // LLVM_CLANG_AST_TYPELOC_H diff --git a/clang/lib/AST/ASTTypeTraits.cpp b/clang/lib/AST/ASTTypeTraits.cpp --- a/clang/lib/AST/ASTTypeTraits.cpp +++ b/clang/lib/AST/ASTTypeTraits.cpp @@ -16,6 +16,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/OpenMPClause.h" #include "clang/AST/TypeLoc.h" @@ -52,6 +53,7 @@ {NKI_None, "Attr"}, #define ATTR(A) {NKI_Attr, #A "Attr"}, #include "clang/Basic/AttrList.inc" + {NKI_None, "ObjCProtocolLoc"}, }; bool ASTNodeKind::isBaseOf(ASTNodeKind Other, unsigned *Distance) const { @@ -193,6 +195,8 @@ QualType(T, 0).print(OS, PP); else if (const Attr *A = get()) A->printPretty(OS, PP); + else if (const ObjCProtocolLoc *P = get()) + P->Protocol->print(OS, PP); else OS << "Unable to print values of type " << NodeKind.asStringRef() << "\n"; } @@ -228,5 +232,7 @@ return CBS->getSourceRange(); if (const auto *A = get()) return A->getRange(); + if (const ObjCProtocolLoc *P = get()) + return P->getSourceRange(); return SourceRange(); } diff --git a/clang/lib/AST/ParentMapContext.cpp b/clang/lib/AST/ParentMapContext.cpp --- a/clang/lib/AST/ParentMapContext.cpp +++ b/clang/lib/AST/ParentMapContext.cpp @@ -330,6 +330,9 @@ DynTypedNode createDynTypedNode(const NestedNameSpecifierLoc &Node) { return DynTypedNode::create(Node); } +template <> DynTypedNode createDynTypedNode(const ObjCProtocolLoc &Node) { + return DynTypedNode::create(Node); +} /// @} /// A \c RecursiveASTVisitor that builds a map from nodes to their @@ -433,6 +436,12 @@ AttrNode, AttrNode, [&] { return VisitorBase::TraverseAttr(AttrNode); }, &Map.PointerParents); } + bool TraverseObjCProtocolLoc(ObjCProtocolLoc ProtocolLocNode) { + return TraverseNode( + ProtocolLocNode, DynTypedNode::create(ProtocolLocNode), + [&] { return VisitorBase::TraverseObjCProtocolLoc(ProtocolLocNode); }, + &Map.OtherParents); + } // Using generic TraverseNode for Stmt would prevent data-recursion. bool dataTraverseStmtPre(Stmt *StmtNode) {