[libclang] Support for querying the exception specification type through libclang

Summary: This patch exposes the exception specification type (noexcept,
etc.) of a C++ function through libclang and Python clang.cindex.

Reviewers: rsmith, aaron.ballman

Reviewed By: aaron.ballman

Subscribers: jbcoe, cfe-commits

Differential Revision: https://reviews.llvm.org/D34091

Patch by Andrew Bennieston

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@306483 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Jonathan Coe 2017-06-27 22:54:56 +00:00
parent 563c0ec65e
commit 34efc84dff
7 changed files with 205 additions and 3 deletions

View File

@ -1367,6 +1367,30 @@ TemplateArgumentKind.DECLARATION = TemplateArgumentKind(2)
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):
@ -1586,6 +1610,18 @@ class Cursor(Structure):
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 @@ class Type(Structure):
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."""

View File

@ -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

View File

@ -171,7 +171,60 @@ typedef struct CXVersion {
*/
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.
*
@ -3470,6 +3523,13 @@ CINDEX_LINKAGE enum CXCallingConv clang_getFunctionTypeCallingConv(CXType T);
*/
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.
@ -3498,6 +3558,13 @@ CINDEX_LINKAGE unsigned clang_isFunctionTypeVariadic(CXType T);
*/
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.

View File

@ -145,6 +145,13 @@ void test(TestColl coll) {
const int operator""_toint(unsigned long long val) { return int(val); }
// noexcept specifications
void f_noexcept() noexcept;
template <class T> 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 @@ const int operator""_toint(unsigned long long val) { return int(val); }
// 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 @@ const int operator""_toint(unsigned long long val) { return int(val); }
// 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])

View File

@ -809,6 +809,37 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
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;

View File

@ -684,6 +684,24 @@ CXType clang_getCursorResultType(CXCursor C) {
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<FunctionProtoType>())
return static_cast<int>(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())

View File

@ -175,6 +175,7 @@ clang_getCursorCompletionString
clang_getCursorDefinition
clang_getCursorDisplayName
clang_getCursorExtent
clang_getCursorExceptionSpecificationType
clang_getCursorKind
clang_getCursorKindSpelling
clang_getCursorLanguage
@ -210,6 +211,7 @@ clang_getElementType
clang_getEnumConstantDeclUnsignedValue
clang_getEnumConstantDeclValue
clang_getEnumDeclIntegerType
clang_getExceptionSpecificationType
clang_getFieldDeclBitWidth
clang_getExpansionLocation
clang_getFile