mirror of https://github.com/microsoft/clang.git
[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:
parent
563c0ec65e
commit
34efc84dff
|
@ -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."""
|
||||
|
|
|
@ -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
|
|
@ -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.
|
||||
|
|
|
@ -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])
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue