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(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(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_ExplicitInstantiationDef