Add libclang capabilities to retriete template arguments from specializations.
Includes Python bindings.
Reviewed in http://reviews.llvm.org/D5621
Patch by Rob Springer
llvm-svn: 219529
diff --git a/clang/tools/c-index-test/c-index-test.c b/clang/tools/c-index-test/c-index-test.c
index d7c28dd..56e4101 100644
--- a/clang/tools/c-index-test/c-index-test.c
+++ b/clang/tools/c-index-test/c-index-test.c
@@ -796,15 +796,42 @@
printf(" [access=%s isVirtual=%s]", accessStr,
isVirtual ? "true" : "false");
}
-
+
SpecializationOf = clang_getSpecializedCursorTemplate(Cursor);
if (!clang_equalCursors(SpecializationOf, clang_getNullCursor())) {
CXSourceLocation Loc = clang_getCursorLocation(SpecializationOf);
CXString Name = clang_getCursorSpelling(SpecializationOf);
clang_getSpellingLocation(Loc, 0, &line, &column, 0);
- printf(" [Specialization of %s:%d:%d]",
+ printf(" [Specialization of %s:%d:%d]",
clang_getCString(Name), line, column);
clang_disposeString(Name);
+
+ if (Cursor.kind == CXCursor_FunctionDecl) {
+ /* Collect the template parameter kinds from the base template. */
+ unsigned NumTemplateArgs = clang_Cursor_getNumTemplateArguments(Cursor);
+ unsigned I;
+ for (I = 0; I < NumTemplateArgs; I++) {
+ enum CXTemplateArgumentKind TAK =
+ clang_Cursor_getTemplateArgumentKind(Cursor, I);
+ switch(TAK) {
+ case CXTemplateArgumentKind_Type:
+ {
+ CXType T = clang_Cursor_getTemplateArgumentType(Cursor, I);
+ CXString S = clang_getTypeSpelling(T);
+ printf(" [Template arg %d: kind: %d, type: %s]",
+ I, TAK, clang_getCString(S));
+ clang_disposeString(S);
+ }
+ break;
+ case CXTemplateArgumentKind_Integral:
+ printf(" [Template arg %d: kind: %d, intval: %lld]",
+ I, TAK, clang_Cursor_getTemplateArgumentValue(Cursor, I));
+ break;
+ default:
+ printf(" [Template arg %d: kind: %d]\n", I, TAK);
+ }
+ }
+ }
}
clang_getOverriddenCursors(Cursor, &overridden, &num_overridden);
diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp
index 782f05e..6590b15 100644
--- a/clang/tools/libclang/CXCursor.cpp
+++ b/clang/tools/libclang/CXCursor.cpp
@@ -1074,6 +1074,140 @@
return clang_getNullCursor();
}
+int clang_Cursor_getNumTemplateArguments(CXCursor C) {
+ if (clang_getCursorKind(C) != CXCursor_FunctionDecl) {
+ return -1;
+ }
+
+ const FunctionDecl *FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(
+ getCursorDecl(C));
+ if (!FD) {
+ return -1;
+ }
+
+ const FunctionTemplateSpecializationInfo* SpecInfo =
+ FD->getTemplateSpecializationInfo();
+ if (!SpecInfo) {
+ return -1;
+ }
+
+ return SpecInfo->TemplateArguments->size();
+}
+
+enum CXGetTemplateArgumentStatus {
+ /** \brief The operation completed successfully */
+ CXGetTemplateArgumentStatus_Success = 0,
+
+ /** \brief The specified cursor did not represent a FunctionDecl. */
+ CXGetTemplateArgumentStatus_CursorNotFunctionDecl = -1,
+
+ /** \brief The specified cursor was not castable to a FunctionDecl. */
+ CXGetTemplateArgumentStatus_BadFunctionDeclCast = -2,
+
+ /** \brief A NULL FunctionTemplateSpecializationInfo was retrieved. */
+ CXGetTemplateArgumentStatus_NullTemplSpecInfo = -3,
+
+ /** \brief An invalid (OOB) argument index was specified */
+ CXGetTemplateArgumentStatus_InvalidIndex = -4
+};
+
+static int clang_Cursor_getTemplateArgument(
+ CXCursor C, unsigned I, TemplateArgument *TA) {
+ if (clang_getCursorKind(C) != CXCursor_FunctionDecl) {
+ return CXGetTemplateArgumentStatus_CursorNotFunctionDecl;
+ }
+
+ const FunctionDecl *FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(
+ getCursorDecl(C));
+ if (!FD) {
+ return CXGetTemplateArgumentStatus_BadFunctionDeclCast;
+ }
+
+ const FunctionTemplateSpecializationInfo* SpecInfo =
+ FD->getTemplateSpecializationInfo();
+ if (!SpecInfo) {
+ return CXGetTemplateArgumentStatus_NullTemplSpecInfo;
+ }
+
+ if (I >= SpecInfo->TemplateArguments->size()) {
+ return CXGetTemplateArgumentStatus_InvalidIndex;
+ }
+
+ *TA = SpecInfo->TemplateArguments->get(I);
+ return 0;
+}
+
+enum CXTemplateArgumentKind clang_Cursor_getTemplateArgumentKind(CXCursor C,
+ unsigned I) {
+ TemplateArgument TA;
+ if (clang_Cursor_getTemplateArgument(C, I, &TA)) {
+ return CXTemplateArgumentKind_Invalid;
+ }
+
+ switch (TA.getKind()) {
+ case TemplateArgument::Null: return CXTemplateArgumentKind_Null;
+ case TemplateArgument::Type: return CXTemplateArgumentKind_Type;
+ case TemplateArgument::Declaration:
+ return CXTemplateArgumentKind_Declaration;
+ case TemplateArgument::NullPtr: return CXTemplateArgumentKind_NullPtr;
+ case TemplateArgument::Integral: return CXTemplateArgumentKind_Integral;
+ case TemplateArgument::Template: return CXTemplateArgumentKind_Template;
+ case TemplateArgument::TemplateExpansion:
+ return CXTemplateArgumentKind_TemplateExpansion;
+ case TemplateArgument::Expression: return CXTemplateArgumentKind_Expression;
+ case TemplateArgument::Pack: return CXTemplateArgumentKind_Pack;
+ }
+
+ return CXTemplateArgumentKind_Invalid;
+}
+
+CXType clang_Cursor_getTemplateArgumentType(CXCursor C, unsigned I) {
+ TemplateArgument TA;
+ if (clang_Cursor_getTemplateArgument(C, I, &TA) !=
+ CXGetTemplateArgumentStatus_Success) {
+ return cxtype::MakeCXType(QualType(), getCursorTU(C));
+ }
+
+ if (TA.getKind() != TemplateArgument::Type) {
+ return cxtype::MakeCXType(QualType(), getCursorTU(C));
+ }
+
+ return cxtype::MakeCXType(TA.getAsType(), getCursorTU(C));
+}
+
+long long clang_Cursor_getTemplateArgumentValue(CXCursor C, unsigned I) {
+ TemplateArgument TA;
+ if (clang_Cursor_getTemplateArgument(C, I, &TA) !=
+ CXGetTemplateArgumentStatus_Success) {
+ assert(0 && "Unable to retrieve TemplateArgument");
+ return 0;
+ }
+
+ if (TA.getKind() != TemplateArgument::Integral) {
+ assert(0 && "Passed template argument is not Integral");
+ return 0;
+ }
+
+ return TA.getAsIntegral().getSExtValue();
+}
+
+unsigned long long clang_Cursor_getTemplateArgumentUnsignedValue(CXCursor C,
+ unsigned I) {
+ TemplateArgument TA;
+ if (clang_Cursor_getTemplateArgument(C, I, &TA) !=
+ CXGetTemplateArgumentStatus_Success) {
+ assert(0 && "Unable to retrieve TemplateArgument");
+ return 0;
+ }
+
+ if (TA.getKind() != TemplateArgument::Integral) {
+ assert(0 && "Passed template argument is not Integral");
+ return 0;
+ }
+
+ return TA.getAsIntegral().getZExtValue();
+}
+
} // end: extern "C"
//===----------------------------------------------------------------------===//
diff --git a/clang/tools/libclang/libclang.exports b/clang/tools/libclang/libclang.exports
index 5a029f7..d7701ad 100644
--- a/clang/tools/libclang/libclang.exports
+++ b/clang/tools/libclang/libclang.exports
@@ -7,6 +7,11 @@
clang_CXXMethod_isStatic
clang_CXXMethod_isVirtual
clang_Cursor_getArgument
+clang_Cursor_getNumTemplateArguments
+clang_Cursor_getTemplateArgumentKind
+clang_Cursor_getTemplateArgumentType
+clang_Cursor_getTemplateArgumentValue
+clang_Cursor_getTemplateArgumentUnsignedValue
clang_Cursor_getBriefCommentText
clang_Cursor_getCommentRange
clang_Cursor_getMangling