Windfisch created this revision. Windfisch added a project: clang-c. Herald added a subscriber: cfe-commits.
Changes `clang_visitChildren()`'s behaviour to also **visit** all explicit and implicit **class template instantiations** upon visiting a `ClassTemplateDecl`. In analogy to clang++'s `-dump-ast` option, they are treated as children of the `ClassTemplateDecl` node. This is done by - adding the `CXCursor_ClassTemplateSpecialization` cursor kind, - adding a `EnforceVisitBody` flag to `CursorVisitor::VisitClassTemplateSpecializationDecl`, which overrides the existing early exits in that method, - and recursively descending into `theTemplateDecl->specializations()`. This patch also adds a query function `clang_getTemplateSpecializationKind` and the associated enum type `CXTemplateSpecializationKind` to retrieve the specialisation kind. That way, users can distinguish between implicit instantiations (which they probably want to visit as child of the ClassTemplateDecl) and explicit instantiation (which they may want choose to ignore, because their node will reappear at the very location where the explicit instantiation takes place). Repository: rC Clang https://reviews.llvm.org/D43763 Files: include/clang-c/Index.h lib/Sema/SemaCodeComplete.cpp tools/libclang/CIndex.cpp tools/libclang/CIndexCXX.cpp tools/libclang/CursorVisitor.h tools/libclang/libclang.exports
Index: tools/libclang/libclang.exports =================================================================== --- tools/libclang/libclang.exports +++ tools/libclang/libclang.exports @@ -259,6 +259,7 @@ clang_getSpellingLocation clang_getTUResourceUsageName clang_getTemplateCursorKind +clang_getTemplateSpecializationKind clang_getTokenExtent clang_getTokenKind clang_getTokenLocation Index: tools/libclang/CIndexCXX.cpp =================================================================== --- tools/libclang/CIndexCXX.cpp +++ tools/libclang/CIndexCXX.cpp @@ -80,6 +80,25 @@ return CXCursor_NoDeclFound; } +enum CXTemplateSpecializationKind clang_getTemplateSpecializationKind(CXCursor C) { + using namespace clang::cxcursor; + + if (C.kind == CXCursor_ClassTemplateSpecialization) + { + switch (static_cast<const ClassTemplateSpecializationDecl *>(getCursorDecl(C))->getSpecializationKind()) + { + #define TRANSL(val) case val: return CX##val; + TRANSL(TSK_Undeclared) + TRANSL(TSK_ImplicitInstantiation) + TRANSL(TSK_ExplicitSpecialization) + TRANSL(TSK_ExplicitInstantiationDeclaration) + TRANSL(TSK_ExplicitInstantiationDefinition) + #undef TRANSL + } + } + return CXTSK_Undeclared; +} + CXCursor clang_getSpecializedCursorTemplate(CXCursor C) { if (!clang_isDeclaration(C.kind)) return clang_getNullCursor(); Index: tools/libclang/CursorVisitor.h =================================================================== --- tools/libclang/CursorVisitor.h +++ tools/libclang/CursorVisitor.h @@ -205,7 +205,7 @@ bool VisitTranslationUnitDecl(TranslationUnitDecl *D); bool VisitTypedefDecl(TypedefDecl *D); bool VisitTagDecl(TagDecl *D); - bool VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *D); + bool VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *D, bool EnforceVisitBody = false); bool VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D); bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); Index: tools/libclang/CIndex.cpp =================================================================== --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -498,7 +498,13 @@ if (!D) return false; - return VisitAttributes(D) || Visit(D); + if (VisitAttributes(D)) + return true; + + if (Cursor.kind == CXCursor_ClassTemplateSpecialization) + return VisitClassTemplateSpecializationDecl(static_cast<ClassTemplateSpecializationDecl*>(D), /*EnforceVisitBody*/ true); + else + return Visit(D); } if (clang_isStatement(Cursor.kind)) { @@ -701,22 +707,23 @@ } bool CursorVisitor::VisitClassTemplateSpecializationDecl( - ClassTemplateSpecializationDecl *D) { - bool ShouldVisitBody = false; - switch (D->getSpecializationKind()) { - case TSK_Undeclared: - case TSK_ImplicitInstantiation: - // Nothing to visit - return false; - - case TSK_ExplicitInstantiationDeclaration: - case TSK_ExplicitInstantiationDefinition: - break; - - case TSK_ExplicitSpecialization: - ShouldVisitBody = true; - break; - } + ClassTemplateSpecializationDecl *D, bool EnforceVisitBody) { + bool ShouldVisitBody = EnforceVisitBody; + if (!EnforceVisitBody) + switch (D->getSpecializationKind()) { + case TSK_Undeclared: + case TSK_ImplicitInstantiation: + // Nothing to visit + return false; + + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + break; + + case TSK_ExplicitSpecialization: + ShouldVisitBody = true; + break; + } // Visit the template arguments used in the specialization. if (TypeSourceInfo *SpecType = D->getTypeAsWritten()) { @@ -939,7 +946,18 @@ return true; auto* CD = D->getTemplatedDecl(); - return VisitAttributes(CD) || VisitCXXRecordDecl(CD); + if (VisitAttributes(CD)) + return true; + if (VisitCXXRecordDecl(CD)) + return true; + + for (auto *Child : D->specializations()) + if (Visit(MakeCXCursor(Child, TU))) + return true; // FIXME do this for function and var templates too. + // inspired by tools/clang/lib/AST/ASTDumper.cpp, ASTDumper::VisitTemplateDecl + // which is called from VisitClassTemplateDecl etc. + + return false; } bool CursorVisitor::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { Index: lib/Sema/SemaCodeComplete.cpp =================================================================== --- lib/Sema/SemaCodeComplete.cpp +++ lib/Sema/SemaCodeComplete.cpp @@ -3222,6 +3222,8 @@ case Decl::AccessSpec: return CXCursor_CXXAccessSpecifier; case Decl::ClassTemplatePartialSpecialization: return CXCursor_ClassTemplatePartialSpecialization; + case Decl::ClassTemplateSpecialization: + return CXCursor_ClassTemplateSpecialization; case Decl::UsingDirective: return CXCursor_UsingDirective; case Decl::StaticAssert: return CXCursor_StaticAssert; case Decl::Friend: return CXCursor_FriendDecl; Index: include/clang-c/Index.h =================================================================== --- include/clang-c/Index.h +++ include/clang-c/Index.h @@ -2578,6 +2578,31 @@ CXCursor_OverloadCandidate = 700 }; +/** + * \brief Describes the kind of template specialization a cursor refers to. + */ +enum CXTemplateSpecializationKind { + + /// This template specialization was formed from a template-id but + /// has not yet been declared, defined, or instantiated. + CXTSK_Undeclared = 0, + /// This template specialization was implicitly instantiated from a + /// template. (C++ [temp.inst]). + CXTSK_ImplicitInstantiation, + /// This template specialization was declared or defined by an + /// explicit specialization (C++ [temp.expl.spec]) or partial + /// specialization (C++ [temp.class.spec]). + CXTSK_ExplicitSpecialization, + /// This template specialization was instantiated from a template + /// due to an explicit instantiation declaration request + /// (C++11 [temp.explicit]). + CXTSK_ExplicitInstantiationDeclaration, + /// This template specialization was instantiated from a template + /// due to an explicit instantiation definition request + /// (C++ [temp.explicit]). + CXTSK_ExplicitInstantiationDefinition +}; + /** * \brief A cursor representing some element in the abstract syntax tree for * a translation unit. @@ -4599,6 +4624,24 @@ * \c CXCursor_NoDeclFound. */ CINDEX_LINKAGE enum CXCursorKind clang_getTemplateCursorKind(CXCursor C); + +/** + * \brief Given a cursor that represents a template, determine the kind + * of specialization (e.g. implicit or explicit instantiation) + * + * This routine can be used to eliminate duplicate explicit template + * instantiations that occur both as a child of the template, and at + * the place where they got explicitly instantiated. By ignoring explicit + * instantiations which parent is / isn't the template itself, no + * duplicates will occur. + * + * \param C The cursor to query. This cursor should represent a template + * declaration. + * + * \returns The template specialization kind. If \p C is not a template, returns + * \c CXTSK_Undeclared. + */ +CINDEX_LINKAGE enum CXTemplateSpecializationKind clang_getTemplateSpecializationKind(CXCursor C); /** * \brief Given a cursor that may represent a specialization or instantiation
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits