Factored out common code between clang_Cursor_getTemplateArgumentType,
clang_Cursor_getTemplateArgumentValue, and
clang_Cursor_getTemplateArgumentUnsignedValue, and simplified test cases.
http://reviews.llvm.org/D5621
Files:
bindings/python/clang/cindex.py
bindings/python/tests/cindex/test_cursor.py
include/clang-c/Index.h
test/Index/preamble_macro_template.cpp
tools/c-index-test/c-index-test.c
tools/libclang/CXCursor.cpp
tools/libclang/libclang.exports
Index: bindings/python/clang/cindex.py
===================================================================
--- bindings/python/clang/cindex.py
+++ bindings/python/clang/cindex.py
@@ -1378,6 +1378,22 @@
for i in range(0, num_args):
yield conf.lib.clang_Cursor_getArgument(self, i)
+ def get_num_template_arguments(self):
+ """Returns the number of template args associated with this cursor."""
+ return conf.lib.clang_Cursor_getNumTemplateArguments(self)
+
+ def get_template_argument_type(self, num):
+ """Returns the CXType for the indicated template argument."""
+ return conf.lib.clang_Cursor_getTemplateArgumentType(self, num)
+
+ def get_template_argument_value(self, num):
+ """Returns the value of the indicated arg as a signed 64b integer."""
+ return conf.lib.clang_Cursor_getTemplateArgumentValue(self, num)
+
+ def get_template_argument_unsigned_value(self, num):
+ """Returns the value of the indicated arg as an unsigned 64b integer."""
+ return conf.lib.clang_Cursor_getTemplateArgumentUnsignedValue(self, num)
+
def get_children(self):
"""Return an iterator for accessing the children of this cursor."""
@@ -3314,6 +3330,23 @@
Cursor,
Cursor.from_result),
+ ("clang_Cursor_getNumTemplateArguments",
+ [Cursor],
+ c_int),
+
+ ("clang_Cursor_getTemplateArgumentType",
+ [Cursor, c_uint],
+ Type,
+ Type.from_result),
+
+ ("clang_Cursor_getTemplateArgumentValue",
+ [Cursor, c_uint],
+ c_longlong),
+
+ ("clang_Cursor_getTemplateArgumentUnsignedValue",
+ [Cursor, c_uint],
+ c_ulonglong),
+
("clang_Cursor_isBitField",
[Cursor],
bool),
Index: bindings/python/tests/cindex/test_cursor.py
===================================================================
--- bindings/python/tests/cindex/test_cursor.py
+++ bindings/python/tests/cindex/test_cursor.py
@@ -1,3 +1,4 @@
+import ctypes
import gc
from clang.cindex import CursorKind
@@ -244,6 +245,41 @@
assert arguments[0].spelling == "i"
assert arguments[1].spelling == "j"
+kTemplateArgTest = """\
+ template <int kInt, typename T, bool kBool>
+ void foo();
+
+ template<>
+ void foo<-7, float, true>();
+ """
+
+def test_get_num_template_arguments():
+ tu = get_tu(kTemplateArgTest, lang='cpp')
+ foos = get_cursors(tu, 'foo')
+
+ assert foos[1].get_num_template_arguments() == 3
+
+def test_get_template_argument_type():
+ tu = get_tu(kTemplateArgTest, lang='cpp')
+ foos = get_cursors(tu, 'foo')
+
+ assert foos[1].get_template_argument_type(1).kind == TypeKind.FLOAT
+
+def test_get_template_argument_value():
+ tu = get_tu(kTemplateArgTest, lang='cpp')
+ foos = get_cursors(tu, 'foo')
+
+ assert foos[1].get_template_argument_value(0) == -7
+ assert foos[1].get_template_argument_value(2) == True
+
+
+def test_get_template_argument_unsigned_value():
+ tu = get_tu(kTemplateArgTest, lang='cpp')
+ foos = get_cursors(tu, 'foo')
+
+ assert foos[1].get_template_argument_unsigned_value(0) == 2 ** 32 - 7
+ assert foos[1].get_template_argument_unsigned_value(2) == True
+
def test_referenced():
tu = get_tu('void foo(); void bar() { foo(); }')
foo = get_cursor(tu, 'foo')
Index: include/clang-c/Index.h
===================================================================
--- include/clang-c/Index.h
+++ include/clang-c/Index.h
@@ -2939,6 +2939,87 @@
CINDEX_LINKAGE CXCursor clang_Cursor_getArgument(CXCursor C, unsigned i);
/**
+ *\brief Returns the number of template args of a function decl representing a
+ * template specialization.
+ *
+ * If the argument cursor cannot be converted into a template function
+ * declaration, -1 is returned.
+ *
+ * For example, for the following declaration and specialization:
+ * template <typename T, int kInt, bool kBool>
+ * void foo() { ... }
+ *
+ * template <>
+ * void foo<float, -7, true>();
+ *
+ * When this is called, 3 will be returned.
+ */
+CINDEX_LINKAGE int clang_Cursor_getNumTemplateArguments(CXCursor C);
+
+/**
+ * \brief Retrieve a CXType representing the type of a TemplateArgument of a
+ * function decl representing a template specialization.
+ *
+ * If the argument CXCursor does not represent a FunctionDecl whose I'th
+ * template argument has a kind of ArgKind::Integral, an invalid type is\
+ * returned (in debug mode, this will assert).
+ *
+ * For example, for the following declaration and specialization:
+ * template <typename T, int kInt, bool kBool>
+ * void foo() { ... }
+ *
+ * template <>
+ * void foo<float, -7, true>();
+ *
+ * If called with I = 0, "float", will be returned.
+ * Invalid types will be returned for I == 1 or 2.
+ */
+CINDEX_LINKAGE CXType clang_Cursor_getTemplateArgumentType(CXCursor C,
+ unsigned I);
+
+/**
+ * \brief Retrieve the value of an Integral TemplateArgument (of a function
+ * decl representing a template specialization) as a signed long long.
+ *
+ * If the argument CXCursor does not represent a FunctionDecl whose I'th
+ * template argument has a kind of ArgKind::Integral, an undefined value will be
+ * returned (in debug mode, this call will fail an assert).
+ *
+ * For example, for the following declaration and specialization:
+ * template <typename T, int kInt, bool kBool>
+ * void foo() { ... }
+ *
+ * template <>
+ * void foo<float, -7, true>();
+ *
+ * If called with I = 1 or 2, -7 or true will be returned, respectively.
+ * For I == 0, an invalid value will be returned or an assert will be triggered.
+ */
+CINDEX_LINKAGE long long clang_Cursor_getTemplateArgumentValue(CXCursor C,
+ unsigned I);
+
+/**
+ * \brief Retrieve the value of an Integral TemplateArgument (of a function
+ * decl representing a template specialization) as an unsigned long long.
+ *
+ * If the argument CXCursor does not represent an TemplateArgument with a kind
+ * ArgKind::Integral, an undefined value will be returned (in debug mode, this
+ * call will fail an assert).
+ *
+ * For example, for the following declaration and specialization:
+ * template <typename T, int kInt, bool kBool>
+ * void foo() { ... }
+ *
+ * template <>
+ * void foo<float, -7, true>();
+ *
+ * If called with I = 1 or 2, 2^32 - 7 or true will be returned, respectively.
+ * For I == 0, an invalid value will be returned or an assert will be triggered.
+ */
+CINDEX_LINKAGE unsigned long long clang_Cursor_getTemplateArgumentUnsignedValue(
+ CXCursor C, unsigned I);
+
+/**
* \brief Determine whether two CXTypes represent the same type.
*
* \returns non-zero if the CXTypes represent the same type and
Index: test/Index/preamble_macro_template.cpp
===================================================================
--- test/Index/preamble_macro_template.cpp
+++ test/Index/preamble_macro_template.cpp
@@ -4,7 +4,7 @@
// RUN: c-index-test -write-pch %t.pch -fno-delayed-template-parsing -x c++-header %S/Inputs/preamble_macro_template.h
// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 local -fno-delayed-template-parsing -I %S/Inputs -include %t %s 2>&1 | tee %t.check.txt | FileCheck %s
-// CHECK: preamble_macro_template.h:4:6: FunctionDecl=foo:4:6 (Definition) [Specialization of foo:4:6] Extent=[4:1 - 6:2]
+// CHECK: preamble_macro_template.h:4:6: FunctionDecl=foo:4:6 (Definition) [Specialization of foo:4:6] [Template arg 0: type: int] Extent=[4:1 - 6:2]
// CHECK: preamble_macro_template.h:4:13: ParmDecl=p:4:13 (Definition) Extent=[4:10 - 4:14]
// CHECK: preamble_macro_template.h:4:16: CompoundStmt= Extent=[4:16 - 6:2]
// CHECK: preamble_macro_template.h:5:3: CStyleCastExpr= Extent=[5:3 - 5:27]
Index: tools/c-index-test/c-index-test.c
===================================================================
--- tools/c-index-test/c-index-test.c
+++ tools/c-index-test/c-index-test.c
@@ -639,6 +639,18 @@
return (int)lhs->col - (int)rhs->col;
}
+typedef struct {
+ enum CXCursorKind *TemplateParamKinds;
+ unsigned CurrentIndex;
+} VisitTemplateParamsData;
+
+enum CXChildVisitResult visitTemplateParams(CXCursor Cursor, CXCursor Parent,
+ CXClientData ClientData) {
+ VisitTemplateParamsData *VTPD = (VisitTemplateParamsData*) ClientData;
+ VTPD->TemplateParamKinds[VTPD->CurrentIndex++] = clang_getCursorKind(Cursor);
+ return CXChildVisit_Continue;
+}
+
static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor);
if (clang_isInvalid(Cursor.kind)) {
@@ -796,15 +808,41 @@
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);
+ enum CXCursorKind *TemplateParamKinds = (enum CXCursorKind*)
+ malloc(NumTemplateArgs * sizeof(enum CXCursorKind));
+ VisitTemplateParamsData VTPD;
+ VTPD.TemplateParamKinds = TemplateParamKinds;
+ VTPD.CurrentIndex = 0;
+ clang_visitChildren(SpecializationOf, visitTemplateParams,
+ &VTPD);
+
+ for (unsigned I = 0; I < NumTemplateArgs; I++) {
+ if (TemplateParamKinds[I] == CXCursor_TemplateTypeParameter) {
+ CXType T = clang_Cursor_getTemplateArgumentType(Cursor, I);
+ CXString S = clang_getTypeSpelling(T);
+ printf(" [Template arg %d: type: %s]", I, clang_getCString(S));
+ clang_disposeString(S);
+ } else if (TemplateParamKinds[I] ==
+ CXCursor_NonTypeTemplateParameter) {
+ printf(" [Template arg %d: intval: %lld]",
+ I, clang_Cursor_getTemplateArgumentValue(Cursor, I));
+ }
+ }
+ free(TemplateParamKinds);
+ }
}
clang_getOverriddenCursors(Cursor, &overridden, &num_overridden);
Index: tools/libclang/CXCursor.cpp
===================================================================
--- tools/libclang/CXCursor.cpp
+++ tools/libclang/CXCursor.cpp
@@ -1071,6 +1071,101 @@
return clang_getNullCursor();
}
+int clang_Cursor_getNumTemplateArguments(CXCursor C) {
+ if (clang_getCursorKind(C) != CXCursor_FunctionDecl) {
+ assert(0 && "Cursor is not a FunctionDecl");
+ return -1;
+ }
+
+ const FunctionDecl *FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(
+ getCursorDecl(C));
+ if (!FD) {
+ assert(0 && "Cursor decl not dyn_cast-able to FunctionDecl");
+ return -1;
+ }
+
+ const FunctionTemplateSpecializationInfo* SpecInfo =
+ FD->getTemplateSpecializationInfo();
+ if (!SpecInfo) {
+ assert(0 && "NULL FunctionTemplateSpecializationInfo retrieved");
+ return -1;
+ }
+
+ return SpecInfo->TemplateArguments->size();
+}
+
+static bool clang_Cursor_getTemplateArgument(
+ CXCursor C, unsigned I, TemplateArgument *TA) {
+ if (clang_getCursorKind(C) != CXCursor_FunctionDecl) {
+ assert(0 && "Cursor is not a FunctionDecl");
+ return false;
+ }
+
+ const FunctionDecl *FD = llvm::dyn_cast_or_null<clang::FunctionDecl>(
+ getCursorDecl(C));
+ if (!FD) {
+ assert(0 && "Cursor decl not dyn_cast-able to FunctionDecl");
+ return false;
+ }
+
+ const FunctionTemplateSpecializationInfo* SpecInfo =
+ FD->getTemplateSpecializationInfo();
+ if (!SpecInfo) {
+ assert(0 && "NULL FunctionTemplateSpecializationInfo retrieved");
+ return false;
+ }
+
+ if (I >= SpecInfo->TemplateArguments->size()) {
+ assert(0 && "Invalid template argument index");
+ return false;
+ }
+
+ *TA = SpecInfo->TemplateArguments->get(I);
+ return true;
+}
+
+CXType clang_Cursor_getTemplateArgumentType(CXCursor C, unsigned I) {
+ TemplateArgument TA;
+ if (!clang_Cursor_getTemplateArgument(C, I, &TA)) {
+ return cxtype::MakeCXType(QualType(), getCursorTU(C));
+ }
+
+ if (TA.getKind() != TemplateArgument::Type) {
+ assert(0 && "Passed template argument is not a 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)) {
+ 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)) {
+ return 0;
+ }
+
+ if (TA.getKind() != TemplateArgument::Integral) {
+ assert(0 && "Passed template argument is not Integral");
+ return 0;
+ }
+
+ return TA.getAsIntegral().getZExtValue();
+}
+
} // end: extern "C"
//===----------------------------------------------------------------------===//
Index: tools/libclang/libclang.exports
===================================================================
--- tools/libclang/libclang.exports
+++ tools/libclang/libclang.exports
@@ -7,6 +7,10 @@
clang_CXXMethod_isStatic
clang_CXXMethod_isVirtual
clang_Cursor_getArgument
+clang_Cursor_getNumTemplateArguments
+clang_Cursor_getTemplateArgumentType
+clang_Cursor_getTemplateArgumentValue
+clang_Cursor_getTemplateArgumentUnsignedValue
clang_Cursor_getBriefCommentText
clang_Cursor_getCommentRange
clang_Cursor_getMangling
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits