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,70 @@ assert arguments[0].spelling == "i" assert arguments[1].spelling == "j" +kTemplateArgTest = """\ + template + 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') + + found = False + for foo in foos: + if foo.kind == CursorKind.FUNCTION_DECL: + found = True + num_template_args = foo.get_num_template_arguments() + assert num_template_args == 3 + assert found + +def test_get_template_argument_type(): + tu = get_tu(kTemplateArgTest, lang='cpp') + foos = get_cursors(tu, 'foo') + + found = False + for foo in foos: + if foo.kind == CursorKind.FUNCTION_DECL: + found = True + assert foo.get_template_argument_type(1).kind == TypeKind.FLOAT + assert found + +def test_get_template_argument_value(): + tu = get_tu(kTemplateArgTest, lang='cpp') + foos = get_cursors(tu, 'foo') + + found = False + for foo in foos: + if foo.kind == CursorKind.FUNCTION_DECL: + found = True + assert ctypes.c_int(foo.get_template_argument_value(0)).value == -7 + assert ctypes.c_bool(foo.get_template_argument_value(2)).value == True + assert found + + +def test_get_template_argument_unsigned_value(): + tu = get_tu(""" + template + void foo(); + + template<> + void foo<-7, float, true>(); + """, lang='cpp') + foos = get_cursors(tu, 'foo') + + found = False + for foo in foos: + if foo.kind == CursorKind.FUNCTION_DECL: + found = True + assert ctypes.c_uint( + foo.get_template_argument_unsigned_value(0)).value == 2 ** 32 - 7 + assert ctypes.c_bool( + foo.get_template_argument_unsigned_value(2)).value == True + assert found + 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,46 @@ CINDEX_LINKAGE CXCursor clang_Cursor_getArgument(CXCursor C, unsigned i); /** + *\brief Returns the number of template args of a template function decl. + * + * If the argument cursor cannot be converted into a template function + * declaration, -1 is returned. + */ +CINDEX_LINKAGE int clang_Cursor_getNumTemplateArguments(CXCursor C); + +/** + * \brief Retrieve a CXType representing the type of a TemplateArgument. + * + * 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). + */ +CINDEX_LINKAGE CXType clang_Cursor_getTemplateArgumentType(CXCursor C, + unsigned I); + +/** + * \brief Retrieve the value of an Integral TemplateArgument 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). + */ +CINDEX_LINKAGE long long clang_Cursor_getTemplateArgumentValue(CXCursor C, + unsigned I); + +/** + * \brief Retrieve the value of an Integral TemplateArgument 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). + */ +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,103 @@ 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( + 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 0; + } + + return SpecInfo->TemplateArguments->size(); +} + +CXType clang_Cursor_getTemplateArgumentType(CXCursor C, unsigned I) { + if (clang_getCursorKind(C) != CXCursor_FunctionDecl) { + assert(0 && "Cursor is not a FunctionDecl"); + return cxtype::MakeCXType(QualType(), getCursorTU(C)); + } + + const FunctionDecl *FD = llvm::dyn_cast_or_null( + getCursorDecl(C)); + if (!FD) { + assert(0 && "Cursor decl not dyn_cast-able to FunctionDecl"); + return cxtype::MakeCXType(QualType(), getCursorTU(C)); + } + + const FunctionTemplateSpecializationInfo* SpecInfo = + FD->getTemplateSpecializationInfo(); + if (!SpecInfo) { + assert(0 && "NULL FunctionTemplateSpecializationInfo retrieved"); + return cxtype::MakeCXType(QualType(), getCursorTU(C)); + } + + if (I >= SpecInfo->TemplateArguments->size()) { + assert(0 && "Invalid template argument index"); + return cxtype::MakeCXType(QualType(), getCursorTU(C)); + } + + TemplateArgument TA = SpecInfo->TemplateArguments->get(I); + 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) { + return static_cast( + clang_Cursor_getTemplateArgumentUnsignedValue(C, I)); +} + +unsigned long long clang_Cursor_getTemplateArgumentUnsignedValue(CXCursor C, + unsigned I) { + if (clang_getCursorKind(C) != CXCursor_FunctionDecl) { + assert(0 && "Cursor is not a FunctionDecl"); + return 0; + } + + const FunctionDecl *FD = llvm::dyn_cast_or_null( + getCursorDecl(C)); + if (!FD) { + assert(0 && "Cursor decl not dyn_cast-able to FunctionDecl"); + return 0; + } + + const FunctionTemplateSpecializationInfo* SpecInfo = + FD->getTemplateSpecializationInfo(); + if (!SpecInfo) { + assert(0 && "NULL FunctionTemplateSpecializationInfo retrieved"); + return 0; + } + + if (I >= SpecInfo->TemplateArguments->size()) { + assert(0 && "Invalid template argument index"); + return 0; + } + + TemplateArgument TA = SpecInfo->TemplateArguments->get(I); + 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