Index: bindings/python/clang/cindex.py =================================================================== --- bindings/python/clang/cindex.py +++ bindings/python/clang/cindex.py @@ -1367,6 +1367,30 @@ TemplateArgumentKind.NULLPTR = TemplateArgumentKind(3) TemplateArgumentKind.INTEGRAL = TemplateArgumentKind(4) +### Exception Specification Kinds ### +class ExceptionSpecificationKind(BaseEnumeration): + """ + An ExceptionSpecificationKind describes the kind of exception specification + that a function has. + """ + + # The required BaseEnumeration declarations. + _kinds = [] + _name_map = None + + def __repr__(self): + return 'ExceptionSpecificationKind.{}'.format(self.name) + +ExceptionSpecificationKind.NONE = ExceptionSpecificationKind(0) +ExceptionSpecificationKind.DYNAMIC_NONE = ExceptionSpecificationKind(1) +ExceptionSpecificationKind.DYNAMIC = ExceptionSpecificationKind(2) +ExceptionSpecificationKind.MS_ANY = ExceptionSpecificationKind(3) +ExceptionSpecificationKind.BASIC_NOEXCEPT = ExceptionSpecificationKind(4) +ExceptionSpecificationKind.COMPUTED_NOEXCEPT = ExceptionSpecificationKind(5) +ExceptionSpecificationKind.UNEVALUATED = ExceptionSpecificationKind(6) +ExceptionSpecificationKind.UNINSTANTIATED = ExceptionSpecificationKind(7) +ExceptionSpecificationKind.UNPARSED = ExceptionSpecificationKind(8) + ### Cursors ### class Cursor(Structure): @@ -1587,6 +1611,18 @@ return self._result_type @property + def exception_specification_kind(self): + ''' + Retrieve the exception specification kind, which is one of the values + from the ExceptionSpecificationKind enumeration. + ''' + if not hasattr(self, '_exception_specification_kind'): + exc_kind = conf.lib.clang_getCursorExceptionSpecificationType(self) + self._exception_specification_kind = ExceptionSpecificationKind.from_id(exc_kind) + + return self._exception_specification_kind + + @property def underlying_typedef_type(self): """Return the underlying type of a typedef declaration. @@ -2254,6 +2290,14 @@ callbacks['fields_visit'](visitor), fields) return iter(fields) + def get_exception_specification_kind(self): + """ + Return the kind of the exception specification; a value from + the ExceptionSpecificationKind enumeration. + """ + return ExceptionSpecificationKind.from_id( + conf.lib.clang.getExceptionSpecificationType(self)) + @property def spelling(self): """Retrieve the spelling of this Type.""" Index: bindings/python/tests/cindex/test_exception_specification_kind.py =================================================================== --- /dev/null +++ bindings/python/tests/cindex/test_exception_specification_kind.py @@ -0,0 +1,27 @@ +import clang.cindex +from clang.cindex import ExceptionSpecificationKind +from .util import get_tu + + +def find_function_declarations(node, declarations=[]): + if node.kind == clang.cindex.CursorKind.FUNCTION_DECL: + declarations.append((node.spelling, node.exception_specification_kind)) + for child in node.get_children(): + declarations = find_function_declarations(child, declarations) + return declarations + + +def test_exception_specification_kind(): + source = """int square1(int x); + int square2(int x) noexcept; + int square3(int x) noexcept(noexcept(x * x));""" + + tu = get_tu(source, lang='cpp', flags=['-std=c++14']) + + declarations = find_function_declarations(tu.cursor) + expected = [ + ('square1', ExceptionSpecificationKind.NONE), + ('square2', ExceptionSpecificationKind.BASIC_NOEXCEPT), + ('square3', ExceptionSpecificationKind.COMPUTED_NOEXCEPT) + ] + assert declarations == expected Index: include/clang-c/Index.h =================================================================== --- include/clang-c/Index.h +++ include/clang-c/Index.h @@ -171,7 +171,60 @@ */ int Subminor; } CXVersion; - + +/** + * \brief Describes the exception specification of a cursor. + * + * A negative value indicates that the cursor is not a function declaration. + */ +enum CXCursor_ExceptionSpecificationKind { + + /** + * \brief The cursor has no exception specification. + */ + CXCursor_ExceptionSpecificationKind_None, + + /** + * \brief The cursor has exception specification throw() + */ + CXCursor_ExceptionSpecificationKind_DynamicNone, + + /** + * \brief The cursor has exception specification throw(T1, T2) + */ + CXCursor_ExceptionSpecificationKind_Dynamic, + + /** + * \brief The cursor has exception specification throw(...). + */ + CXCursor_ExceptionSpecificationKind_MSAny, + + /** + * \brief The cursor has exception specification basic noexcept. + */ + CXCursor_ExceptionSpecificationKind_BasicNoexcept, + + /** + * \brief The cursor has exception specification computed noexcept. + */ + CXCursor_ExceptionSpecificationKind_ComputedNoexcept, + + /** + * \brief The exception specification has not yet been evaluated. + */ + CXCursor_ExceptionSpecificationKind_Unevaluated, + + /** + * \brief The exception specification has not yet been instantiated. + */ + CXCursor_ExceptionSpecificationKind_Uninstantiated, + + /** + * \brief The exception specification has not been parsed yet. + */ + CXCursor_ExceptionSpecificationKind_Unparsed +}; + /** * \brief Provides a shared context for creating translation units. * @@ -3471,6 +3524,13 @@ CINDEX_LINKAGE CXType clang_getResultType(CXType T); /** + * \brief Retrieve the exception specification type associated with a function type. + * + * If a non-function type is passed in, an error code of -1 is returned. + */ +CINDEX_LINKAGE int clang_getExceptionSpecificationType(CXType T); + +/** * \brief Retrieve the number of non-variadic parameters associated with a * function type. * @@ -3499,6 +3559,13 @@ CINDEX_LINKAGE CXType clang_getCursorResultType(CXCursor C); /** + * \brief Retrieve the exception specification type associated with a given cursor. + * + * This only returns a valid result if the cursor refers to a function or method. + */ +CINDEX_LINKAGE int clang_getCursorExceptionSpecificationType(CXCursor C); + +/** * \brief Return 1 if the CXType is a POD (plain old data) type, and 0 * otherwise. */ Index: test/Index/get-cursor.cpp =================================================================== --- test/Index/get-cursor.cpp +++ test/Index/get-cursor.cpp @@ -145,6 +145,13 @@ const int operator""_toint(unsigned long long val) { return int(val); } +// noexcept specifications +void f_noexcept() noexcept; +template void f_computed_noexcept(T t) noexcept(noexcept(t+t)); +void f_dynamic_noexcept_none() throw(); +void f_dynamic_noexcept() throw(int); +void f_dynamic_noexcept_any() throw(...); + // RUN: c-index-test -cursor-at=%s:6:4 %s | FileCheck -check-prefix=CHECK-COMPLETION-1 %s // CHECK-COMPLETION-1: CXXConstructor=X:6:3 // CHECK-COMPLETION-1-NEXT: Completion string: {TypedText X}{LeftParen (}{Placeholder int}{Comma , }{Placeholder int}{RightParen )} @@ -209,11 +216,11 @@ // RUN: c-index-test -cursor-at=%s:66:23 %s | FileCheck -check-prefix=CHECK-TEMPLSPEC %s // CHECK-TEMPLSPEC: 66:23 ClassDecl=TC:66:23 (Definition) [Specialization of TC:59:7] Extent=[66:1 - 66:31] Spelling=TC ([66:23 - 66:25]) -// RUN: c-index-test -cursor-at=%s:69:3 -cursor-at=%s:70:11 -cursor-at=%s:73:6 -cursor-at=%s:74:6 -cursor-at=%s:77:8 -cursor-at=%s:78:8 -cursor-at=%s:79:8 -cursor-at=%s:80:8 -cursor-at=%s:81:8 -cursor-at=%s:82:8 -cursor-at=%s:85:6 -cursor-at=%s:86:6 -cursor-at=%s:87:6 -cursor-at=%s:88:6 -cursor-at=%s:91:5 -cursor-at=%s:92:5 -cursor-at=%s:93:5 -cursor-at=%s:94:5 -cursor-at=%s:95:5 -cursor-at=%s:96:5 -cursor-at=%s:97:5 -cursor-at=%s:98:5 -cursor-at=%s:100:5 -cursor-at=%s:101:5 -cursor-at=%s:104:6 -cursor-at=%s:105:6 -cursor-at=%s:106:6 -cursor-at=%s:107:6 -cursor-at=%s:108:6 -cursor-at=%s:109:6 -cursor-at=%s:110:6 -cursor-at=%s:111:6 -cursor-at=%s:113:6 -cursor-at=%s:114:6 -cursor-at=%s:117:8 -cursor-at=%s:118:8 -cursor-at=%s:120:8 -cursor-at=%s:121:8 -cursor-at=%s:122:8 -cursor-at=%s:123:8 -cursor-at=%s:124:8 -cursor-at=%s:125:8 -cursor-at=%s:128:6 -cursor-at=%s:129:6 -cursor-at=%s:130:6 -cursor-at=%s:132:3 -cursor-at=%s:146:15 -std=c++11 %s | FileCheck -check-prefix=CHECK-SPELLING %s +// RUN: c-index-test -cursor-at=%s:69:3 -cursor-at=%s:70:11 -cursor-at=%s:73:6 -cursor-at=%s:74:6 -cursor-at=%s:77:8 -cursor-at=%s:78:8 -cursor-at=%s:79:8 -cursor-at=%s:80:8 -cursor-at=%s:81:8 -cursor-at=%s:82:8 -cursor-at=%s:85:6 -cursor-at=%s:86:6 -cursor-at=%s:87:6 -cursor-at=%s:88:6 -cursor-at=%s:91:5 -cursor-at=%s:92:5 -cursor-at=%s:93:5 -cursor-at=%s:94:5 -cursor-at=%s:95:5 -cursor-at=%s:96:5 -cursor-at=%s:97:5 -cursor-at=%s:98:5 -cursor-at=%s:100:5 -cursor-at=%s:101:5 -cursor-at=%s:104:6 -cursor-at=%s:105:6 -cursor-at=%s:106:6 -cursor-at=%s:107:6 -cursor-at=%s:108:6 -cursor-at=%s:109:6 -cursor-at=%s:110:6 -cursor-at=%s:111:6 -cursor-at=%s:113:6 -cursor-at=%s:114:6 -cursor-at=%s:117:8 -cursor-at=%s:118:8 -cursor-at=%s:120:8 -cursor-at=%s:121:8 -cursor-at=%s:122:8 -cursor-at=%s:123:8 -cursor-at=%s:124:8 -cursor-at=%s:125:8 -cursor-at=%s:128:6 -cursor-at=%s:129:6 -cursor-at=%s:130:6 -cursor-at=%s:132:3 -cursor-at=%s:146:15 -cursor-at=%s:149:6 -cursor-at=%s:150:25 -cursor-at=%s:151:6 -cursor-at=%s:152:6 -cursor-at=%s:153:6 -std=c++11 %s | FileCheck -check-prefix=CHECK-SPELLING %s // CHECK-SPELLING: 69:3 CXXConstructor=A:69:3 (default constructor) Extent=[69:3 - 69:6] Spelling=A ([69:3 - 69:4]) // CHECK-SPELLING: 70:11 CXXDestructor=~A:70:11 (virtual) Extent=[70:3 - 70:15] Spelling=~A ([70:11 - 70:13]) // CHECK-SPELLING: 73:6 CXXMethod=operator=:73:6 Extent=[73:3 - 73:25] Spelling=operator= ([73:6 - 73:15]) -// CHECK-SPELLING: 74:6 CXXMethod=operator=:74:6 Extent=[74:3 - 74:29] Spelling=operator= ([74:6 - 74:15]) +// CHECK-SPELLING: 74:6 CXXMethod=operator=:74:6 (noexcept) Extent=[74:3 - 74:29] Spelling=operator= ([74:6 - 74:15]) // CHECK-SPELLING: 77:8 CXXMethod=operator+:77:8 (const) Extent=[77:3 - 77:25] Spelling=operator+ ([77:8 - 77:17]) // CHECK-SPELLING: 78:8 CXXMethod=operator-:78:8 (const) Extent=[78:3 - 78:25] Spelling=operator- ([78:8 - 78:17]) // CHECK-SPELLING: 79:8 CXXMethod=operator~:79:8 (const) Extent=[79:3 - 79:25] Spelling=operator~ ([79:8 - 79:17]) @@ -257,8 +264,14 @@ // CHECK-SPELLING: 130:6 CXXMethod=operator():130:6 (const) Extent=[130:3 - 130:37] Spelling=operator() ([130:6 - 130:16]) // CHECK-SPELLING: 132:12 CXXConversion=operator bool:132:12 (const) Extent=[132:3 - 132:33] Spelling=operator bool ([132:12 - 132:25]) // CHECK-SPELLING: 146:11 FunctionDecl=operator""_toint:146:11 (Definition) Extent=[146:1 - 146:72] Spelling=operator""_toint ([146:11 - 146:27]) +// CHECK-SPELLING: 149:6 FunctionDecl=f_noexcept:149:6 (noexcept) Extent=[149:1 - 149:27] Spelling=f_noexcept ([149:6 - 149:16]) +// CHECK-SPELLING: 150:25 FunctionTemplate=f_computed_noexcept:150:25 (computed-noexcept) Extent=[150:1 - 150:73] Spelling=f_computed_noexcept ([150:25 - 150:44]) +// CHECK-SPELLING: 151:6 FunctionDecl=f_dynamic_noexcept_none:151:6 (noexcept dynamic none) Extent=[151:1 - 151:39] Spelling=f_dynamic_noexcept_none ([151:6 - 151:29]) +// CHECK-SPELLING: 152:6 FunctionDecl=f_dynamic_noexcept:152:6 (noexcept dynamic) Extent=[152:1 - 152:37] Spelling=f_dynamic_noexcept ([152:6 - 152:24]) +// CHECK-SPELLING: 153:6 FunctionDecl=f_dynamic_noexcept_any:153:6 (noexcept dynamic any) Extent=[153:1 - 153:41] Spelling=f_dynamic_noexcept_any ([153:6 - 153:28]) // RUN: c-index-test -cursor-at=%s:141:13 -cursor-at=%s:141:18 -cursor-at=%s:142:11 -std=c++11 %s | FileCheck -check-prefix=CHECK-FORRANGE %s // CHECK-FORRANGE: 141:13 VarDecl=lv:141:13 (Definition) Extent=[141:8 - 141:17] Spelling=lv ([141:13 - 141:15]) // CHECK-FORRANGE: 141:18 DeclRefExpr=coll:140:20 Extent=[141:18 - 141:22] Spelling=coll ([141:18 - 141:22]) // CHECK-FORRANGE: 142:11 DeclRefExpr=lv:141:13 Extent=[142:11 - 142:13] Spelling=lv ([142:11 - 142:13]) + 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 @@ -809,6 +809,37 @@ if (clang_Cursor_isObjCOptional(Cursor)) printf(" (@optional)"); + switch (clang_getCursorExceptionSpecificationType(Cursor)) + { + case CXCursor_ExceptionSpecificationKind_None: + break; + + case CXCursor_ExceptionSpecificationKind_DynamicNone: + printf(" (noexcept dynamic none)"); + break; + + case CXCursor_ExceptionSpecificationKind_Dynamic: + printf(" (noexcept dynamic)"); + break; + + case CXCursor_ExceptionSpecificationKind_MSAny: + printf(" (noexcept dynamic any)"); + break; + + case CXCursor_ExceptionSpecificationKind_BasicNoexcept: + printf(" (noexcept)"); + break; + + case CXCursor_ExceptionSpecificationKind_ComputedNoexcept: + printf(" (computed-noexcept)"); + break; + + case CXCursor_ExceptionSpecificationKind_Unevaluated: + case CXCursor_ExceptionSpecificationKind_Uninstantiated: + case CXCursor_ExceptionSpecificationKind_Unparsed: + break; + } + { CXString language; CXString definedIn; Index: tools/libclang/CXType.cpp =================================================================== --- tools/libclang/CXType.cpp +++ tools/libclang/CXType.cpp @@ -684,6 +684,24 @@ return MakeCXType(QualType(), cxcursor::getCursorTU(C)); } +int clang_getExceptionSpecificationType(CXType X) { + QualType T = GetQualType(X); + if (T.isNull()) + return -1; + + if (const auto *FD = T->getAs()) + return static_cast(FD->getExceptionSpecType()); + + return -1; +} + +int clang_getCursorExceptionSpecificationType(CXCursor C) { + if (clang_isDeclaration(C.kind)) + return clang_getExceptionSpecificationType(clang_getCursorType(C)); + + return -1; +} + unsigned clang_isPODType(CXType X) { QualType T = GetQualType(X); if (T.isNull()) Index: tools/libclang/libclang.exports =================================================================== --- tools/libclang/libclang.exports +++ tools/libclang/libclang.exports @@ -175,6 +175,7 @@ clang_getCursorDefinition clang_getCursorDisplayName clang_getCursorExtent +clang_getCursorExceptionSpecificationType clang_getCursorKind clang_getCursorKindSpelling clang_getCursorLanguage @@ -210,6 +211,7 @@ clang_getEnumConstantDeclUnsignedValue clang_getEnumConstantDeclValue clang_getEnumDeclIntegerType +clang_getExceptionSpecificationType clang_getFieldDeclBitWidth clang_getExpansionLocation clang_getFile